mirror of
https://github.com/fugary/simple-element-plus-template.git
synced 2025-11-12 14:27:49 +00:00
依赖设计与控件优化
This commit is contained in:
1759
package-lock.json
generated
1759
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -9,44 +9,48 @@
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
|
||||
"hmr": "vite --debug hmr"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fugary/simple-element-plus-template"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@guolao/vue-monaco-editor": "^1.5.1",
|
||||
"@guolao/vue-monaco-editor": "^1.5.5",
|
||||
"@howiefh/ant-path-matcher": "^0.0.4",
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vueuse/core": "^10.11.0",
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"async-validator": "^4.2.5",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "^1.11.11",
|
||||
"axios": "^1.7.9",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.5.0",
|
||||
"element-plus": "^2.7.5",
|
||||
"element-plus": "^2.9.11",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "^0.47.0",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"nprogress": "^0.2.0",
|
||||
"numeral": "^2.0.6",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"pinia": "^2.3.1",
|
||||
"pinia-plugin-persistedstate": "^3.2.3",
|
||||
"split.js": "^1.6.5",
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"vite-plugin-mock": "^3.0.1",
|
||||
"vue": "^3.4.29",
|
||||
"vue": "^3.4.38",
|
||||
"vue-echarts": "^6.7.3",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-router": "^4.3.3",
|
||||
"vue-i18n": "^9.14.4",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-virtual-scroller": "^2.0.0-beta.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/rollup-win32-x64-msvc": "^4.18.0",
|
||||
"@rushstack/eslint-patch": "^1.10.3",
|
||||
"@rushstack/eslint-patch": "^1.10.5",
|
||||
"@typescript-eslint/eslint-plugin": "^7.13.1",
|
||||
"@typescript-eslint/parser": "^7.13.1",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/eslint-config-standard": "^8.0.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.26.0",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.3.1",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^5.4.19",
|
||||
"vite-plugin-eslint": "^1.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,18 @@ const props = defineProps({
|
||||
|
||||
const calcItems = computed(() => {
|
||||
return props.items.filter(item => item.enabled !== false).map(item => {
|
||||
const label = item.labelKey ? toLabelByKey(item.labelKey) : item.label
|
||||
let label = item.labelKey ? toLabelByKey(item.labelKey) : item.label
|
||||
label = isFunction(item.labelFormatter) ? item.labelFormatter(item) : label
|
||||
const value = isFunction(item.formatter) ? item.formatter(item) : item.value
|
||||
const labelResult = { label, vnode: isVNode(label) }
|
||||
const valueResult = { value, vnode: isVNode(value) }
|
||||
const slotsResult = calcSlotsResult(item)
|
||||
return {
|
||||
...item,
|
||||
label,
|
||||
width: item.width || props.width,
|
||||
minWidth: item.minWidth || props.minWidth,
|
||||
valueResult,
|
||||
labelResult,
|
||||
slotsResult
|
||||
}
|
||||
})
|
||||
@@ -44,7 +46,6 @@ const calcItems = computed(() => {
|
||||
<el-descriptions-item
|
||||
v-for="(calcItem, index) in calcItems"
|
||||
:key="index"
|
||||
:label="calcItem.label"
|
||||
:min-width="calcItem.minWidth"
|
||||
:width="calcItem.width"
|
||||
:span="calcItem.span"
|
||||
@@ -64,6 +65,19 @@ const calcItems = computed(() => {
|
||||
{{ calcItem.slotsResult[slotKey].result }}
|
||||
</template>
|
||||
</template>
|
||||
<template
|
||||
v-if="calcItem.labelResult.label"
|
||||
#label
|
||||
>
|
||||
<span
|
||||
v-if="calcItem.labelResult.label&&!calcItem.labelResult.vnode"
|
||||
v-html="calcItem.labelResult.label"
|
||||
/>
|
||||
<component
|
||||
:is="calcItem.labelResult.label"
|
||||
v-if="calcItem.labelResult.vnode"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="calcItem.valueResult.value">
|
||||
<span
|
||||
v-if="calcItem.valueResult.value&&!calcItem.valueResult.vnode"
|
||||
|
||||
@@ -124,7 +124,7 @@ const slots = computed(() => {
|
||||
<el-link
|
||||
class="margin-left1 margin-top1"
|
||||
type="primary"
|
||||
:underline="false"
|
||||
underline="never"
|
||||
@click="setUnlimited()"
|
||||
>
|
||||
<el-tag
|
||||
|
||||
@@ -57,7 +57,7 @@ const tooltipFunc = ($event) => {
|
||||
>
|
||||
<span>
|
||||
<el-link
|
||||
:underline="false"
|
||||
underline="never"
|
||||
@click="tooltipFunc($event)"
|
||||
>
|
||||
<common-icon
|
||||
|
||||
@@ -258,14 +258,16 @@ const formatResult = computed(() => {
|
||||
:content="calcOption.tooltip"
|
||||
placement="top-start"
|
||||
raw-content
|
||||
v-bind="calcOption.tooltipAttrs"
|
||||
>
|
||||
<span>
|
||||
<el-link
|
||||
:underline="false"
|
||||
v-bind="calcOption.tooltipLinkAttrs"
|
||||
underline="never"
|
||||
@click="calcOption.tooltipFunc"
|
||||
>
|
||||
<common-icon
|
||||
icon="QuestionFilled"
|
||||
:icon="calcOption.tooltipIcon||'QuestionFilled'"
|
||||
/>
|
||||
</el-link>
|
||||
</span>
|
||||
@@ -288,7 +290,7 @@ const formatResult = computed(() => {
|
||||
>
|
||||
<component
|
||||
:is="scope[`__slotResult__${slotKey}`]"
|
||||
v-if="isVNode(scope[`__slotResult__${slotKey}`] = slot(scope))"
|
||||
v-if="isVNode(scope[`__slotResult__${slotKey}`] = slot(scope, calcOption))"
|
||||
/>
|
||||
<template v-else>
|
||||
{{ scope[`__slotResult__${slotKey}`] }}
|
||||
|
||||
7
src/components/common-form/public.d.ts
vendored
7
src/components/common-form/public.d.ts
vendored
@@ -4,6 +4,7 @@ import {
|
||||
InputProps, InputNumberProps, CascaderProps,
|
||||
RadioGroupProps, RadioProps, RadioButtonProps,
|
||||
CheckboxProps, CheckboxGroupProps, CheckboxButtonProps,
|
||||
LinkProps, ElTooltipProps,
|
||||
DatePickerProps, timePickerDefaultProps, SwitchProps, SliderProps, TransferProps
|
||||
} from 'element-plus'
|
||||
import { SelectProps as SelectV1Props } from 'element-plus/es/components/select/src/select'
|
||||
@@ -137,6 +138,12 @@ export interface CommonFormOption extends FormControlTypeOption {
|
||||
change?: (val: any) => void;
|
||||
/** 提示信息 */
|
||||
tooltip?: string;
|
||||
/** 图标 */
|
||||
tooltipIcon?: string;
|
||||
/** tooltip配置 */
|
||||
tooltipAttrs?: ElTooltipProps;
|
||||
/** tooltip link配置 */
|
||||
tooltipLinkAttrs?: LinkProps;
|
||||
/** 提示函数 */
|
||||
tooltipFunc?: () => void;
|
||||
/** 自动trim,默认false**/
|
||||
|
||||
@@ -15,6 +15,14 @@ const calcIcon = computed(() => {
|
||||
}
|
||||
return props.icon
|
||||
})
|
||||
|
||||
const customIcon = computed(() => {
|
||||
if (props.icon?.startsWith('custom')) {
|
||||
return props.icon
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -24,6 +32,12 @@ const calcIcon = computed(() => {
|
||||
>
|
||||
<component
|
||||
:is="calcIcon"
|
||||
v-if="!customIcon"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="custom-icon"
|
||||
:class="customIcon"
|
||||
/>
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
68
src/components/common-split/index.vue
Normal file
68
src/components/common-split/index.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, useAttrs } from 'vue'
|
||||
import Split from 'split.js'
|
||||
|
||||
/**
|
||||
* 更多属性配置可以参考文档
|
||||
* @link https://github.com/nathancahill/split/tree/master/packages/splitjs <br>
|
||||
*/
|
||||
const props = defineProps({
|
||||
sizes: {
|
||||
type: Array,
|
||||
default: () => [25, 75]
|
||||
},
|
||||
minSize: {
|
||||
type: [Number, Array],
|
||||
default: 100
|
||||
},
|
||||
maxSize: {
|
||||
type: [Number, Array],
|
||||
default: Infinity
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal',
|
||||
validator (value) {
|
||||
return ['horizontal', 'vertical'].includes(value)
|
||||
}
|
||||
},
|
||||
gutterAlign: {
|
||||
type: String,
|
||||
default: 'center',
|
||||
validator (value) {
|
||||
return ['start', 'center', 'end'].includes(value)
|
||||
}
|
||||
}
|
||||
})
|
||||
const itemRefs = ref([])
|
||||
|
||||
const attrs = useAttrs()
|
||||
|
||||
onMounted(() => {
|
||||
Split(itemRefs.value.map(itemRef => itemRef), {
|
||||
sizes: props.sizes,
|
||||
minSize: props.minSize,
|
||||
maxSize: props.maxSize,
|
||||
gutterAlign: props.gutterAlign,
|
||||
direction: props.direction,
|
||||
...attrs
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="common-split">
|
||||
<div
|
||||
v-for="(_, index) in sizes"
|
||||
ref="itemRefs"
|
||||
:key="index"
|
||||
>
|
||||
<slot :name="`split-${index}`" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -119,7 +119,7 @@ const options = computed(() => {
|
||||
circle
|
||||
type="danger"
|
||||
size="small"
|
||||
:underline="false"
|
||||
underline="never"
|
||||
@click="deleteItem(row, $index)"
|
||||
>
|
||||
<common-icon
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import { formatDate } from '@/utils'
|
||||
import { computed, useSlots } from 'vue'
|
||||
import { get } from 'lodash-es'
|
||||
import { computed, isVNode, useSlots } from 'vue'
|
||||
import { get, isFunction } from 'lodash-es'
|
||||
import { toLabelByKey } from '@/components/utils'
|
||||
import TableDynamicButton from '@/components/common-table/table-dynamic-button.vue'
|
||||
|
||||
@@ -17,6 +17,10 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
columnIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* @type {''|'large'|'small'|'default'}
|
||||
*/
|
||||
@@ -43,18 +47,45 @@ const getPropertyData = (row) => {
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const columnLabel = computed(() => {
|
||||
return props.column.label || toLabelByKey(props.column.labelKey)
|
||||
})
|
||||
|
||||
const headerResult = computed(() => {
|
||||
const column = props.column
|
||||
if (isFunction(column.headerFormatter)) {
|
||||
const header = column.headerFormatter(column)
|
||||
return { header, vnode: isVNode(header) }
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-table-column
|
||||
v-if="!column.isOperation"
|
||||
:label="column.label || toLabelByKey(column.labelKey)"
|
||||
:key="`${columnLabel}-${columnIndex}`"
|
||||
:label="columnLabel"
|
||||
:prop="column.prop||column.property"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
v-bind="column.attrs"
|
||||
:formatter="formatter"
|
||||
>
|
||||
<template
|
||||
v-if="headerResult"
|
||||
#header
|
||||
>
|
||||
<span
|
||||
v-if="headerResult.header&&!headerResult.vnode"
|
||||
v-html="headerResult.header"
|
||||
/>
|
||||
<component
|
||||
:is="headerResult.header"
|
||||
v-if="headerResult.vnode"
|
||||
/>
|
||||
</template>
|
||||
<template
|
||||
v-if="column.click"
|
||||
#default="scope"
|
||||
|
||||
@@ -267,6 +267,7 @@ defineExpose({
|
||||
<common-table-column
|
||||
v-for="(column, index) in calcColumns"
|
||||
:key="index"
|
||||
:column-index="index"
|
||||
:column="column"
|
||||
:button-size="buttonSize"
|
||||
>
|
||||
|
||||
6
src/components/common-table/public.d.ts
vendored
6
src/components/common-table/public.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import { ButtonProps, LinkProps, TableProps, PaginationProps } from 'element-plus'
|
||||
import tableColumnProps from 'element-plus/es/components/table/src/table-column/defaults'
|
||||
import { CommonPage } from '../public'
|
||||
import { ExtractPropTypes } from 'vue'
|
||||
import { ExtractPropTypes, VNode } from 'vue'
|
||||
|
||||
export type TableColumnProps = ExtractPropTypes<typeof tableColumnProps>
|
||||
|
||||
@@ -52,7 +52,9 @@ export interface CommonTableColumn {
|
||||
/** 点击事件 */
|
||||
click?: (data: any) => any;
|
||||
/** 格式化函数 */
|
||||
formatter?: (data: any, scope: any) => string;
|
||||
formatter?: (data: any, scope: any) => string|VNode;
|
||||
/** header格式化 */
|
||||
headerFormatter?: (data: any, scope: any) => string|VNode;
|
||||
/** 日期格式化 */
|
||||
dateFormat?: string
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ const button = computed(() => {
|
||||
<template>
|
||||
<el-button
|
||||
v-if="button.enabled!==false"
|
||||
v-common-tooltip="button.tooltip"
|
||||
:type="button.type"
|
||||
:size="button.size||buttonSize"
|
||||
:disabled="button.disabled"
|
||||
|
||||
@@ -46,6 +46,7 @@ const getTooltipDirective = (props) => {
|
||||
el.tooltipConfig = calcTooltipConfig(binding)
|
||||
},
|
||||
unmounted (el) {
|
||||
el.tooltipVnode?.component?.exposed?.showOrHideTooltip(false)
|
||||
el.tooltipDynamicHelper?.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import CommonWindow from '@/components/common-window/index.vue'
|
||||
import CommonAutocomplete from '@/components/common-autocomplete/index.vue'
|
||||
import CommonSort from '@/components/common-sort/index.vue'
|
||||
import CommonDescriptions from '@/components/common-descriptions/index.vue'
|
||||
import CommonSplit from '@/components/common-split/index.vue'
|
||||
import CommonDirectives from '@/components/directives'
|
||||
|
||||
/**
|
||||
@@ -44,6 +45,7 @@ export default {
|
||||
Vue.component('CommonAutocomplete', CommonAutocomplete)
|
||||
Vue.component('CommonSort', CommonSort)
|
||||
Vue.component('CommonDescriptions', CommonDescriptions)
|
||||
Vue.component('CommonSplit', CommonSplit)
|
||||
Vue.use(CommonDirectives)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,13 @@ export const proxyMethod = (targets = [], methodName) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const limitStr = (str, len) => {
|
||||
if (str && str.length > len) {
|
||||
return str.substring(0, len) + '...'
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
export const calcSlotsResult = (config, data) => {
|
||||
const results = {}
|
||||
if (config?.slots) {
|
||||
|
||||
@@ -68,7 +68,10 @@ export const useTabsViewStore = defineStore('tabsView', () => {
|
||||
}
|
||||
|
||||
const findHistoryTab = (path) => {
|
||||
const idx = historyTabs.value.findIndex(v => v.path === path)
|
||||
let idx = historyTabs.value.findIndex(v => v.path === path)
|
||||
if (idx === -1) {
|
||||
idx = historyTabs.value.findIndex(v => v.fullPath === path)
|
||||
}
|
||||
if (idx > -1) {
|
||||
return historyTabs.value[idx]
|
||||
}
|
||||
@@ -99,15 +102,22 @@ export const useTabsViewStore = defineStore('tabsView', () => {
|
||||
// 可能是Proxy,需要解析出来
|
||||
isHomeTab(tab) ? historyTabs.value.unshift({ ...tab }) : historyTabs.value.push({ ...tab })
|
||||
}
|
||||
tab.accessTime = Date.now()
|
||||
if (isNestedRoute(tab)) {
|
||||
addNestedParentTab(tab, replaceTab)
|
||||
} else {
|
||||
addCachedTab(tab, replaceTab)
|
||||
}
|
||||
} else {
|
||||
historyTabs.value[idx].accessTime = Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const findLastTab = () => {
|
||||
return historyTabs.value.toSorted((a, b) => b.accessTime - a.accessTime)?.[0]
|
||||
}
|
||||
|
||||
const removeHistoryTab = tab => {
|
||||
if (historyTabs.value.length > 1) {
|
||||
const idx = historyTabs.value.findIndex(v => v.path === tab.path)
|
||||
@@ -116,7 +126,7 @@ export const useTabsViewStore = defineStore('tabsView', () => {
|
||||
// 删除tab
|
||||
historyTabs.value.splice(idx, 1)
|
||||
}
|
||||
return historyTabs.value[historyTabs.value.length - 1]
|
||||
return findLastTab()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,5 +237,7 @@ export const useTabsViewStore = defineStore('tabsView', () => {
|
||||
hasCloseDropdown
|
||||
}
|
||||
}, {
|
||||
persist: { serializer }
|
||||
persist: {
|
||||
serializer
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user