ci-plus 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/index.ts +13 -0
- package/package.json +44 -0
- package/script/build/index.ts +32 -0
- package/script/publish/index.ts +7 -0
- package/script/utils/delpath.ts +30 -0
- package/script/utils/paths.ts +7 -0
- package/script/utils/run.ts +15 -0
- package/src/button/button.vue +41 -0
- package/src/button/index.ts +4 -0
- package/src/button/style/index.less +35 -0
- package/src/buttons/buttons.vue +18 -0
- package/src/buttons/index.ts +4 -0
- package/src/ccapp/ccapp.vue +27 -0
- package/src/ccapp/index.ts +4 -0
- package/src/components.d.ts +18 -0
- package/src/dailog/dialog.vue +266 -0
- package/src/dailog/index.ts +4 -0
- package/src/dailog/style/index.less +69 -0
- package/src/icon/icon.vue +7 -0
- package/src/icon/index.ts +4 -0
- package/src/icon/style/index.less +3 -0
- package/src/index.ts +5 -0
- package/src/sortableTable/headButtons.vue +25 -0
- package/src/sortableTable/headerCheckBox.vue +74 -0
- package/src/sortableTable/headerInput.vue +148 -0
- package/src/sortableTable/headerRange.vue +108 -0
- package/src/sortableTable/headerSelectV2.vue +178 -0
- package/src/sortableTable/sortableTable.ts +4 -0
- package/src/sortableTable/sortableTable.vue +221 -0
- package/src/sortableTable/sortableTableDialog.vue +109 -0
- package/src/sortableTable/utils/dataOpt.ts +65 -0
- package/src/sortableTable/utils/dateShortcuts.ts +72 -0
- package/src/sortableTable/utils/filter.vue +30 -0
- package/src/sortableTable/utils/filterIcon.vue +8 -0
- package/src/sortableTable/utils/headerPopover.vue +92 -0
- package/src/sortableTable/utils/index.d.ts +11 -0
- package/src/sortableTable/utils/interface.ts +52 -0
- package/src/sortableTable/utils/removeParamsFilters.ts +9 -0
- package/src/sortableTable/utils/sortableTableColumnCell.vue +91 -0
- package/src/sortableTable/utils/sortableTableColumnCell2.vue +72 -0
- package/src/sortableTable/utils/sortableTableDragItem.vue +164 -0
- package/src/sortableTable/utils/sortableTableDragItem2.vue +144 -0
- package/src/sortableTable/utils/sortableTableTs.ts +9 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/withinstall/index.ts +12 -0
- package/vite.config.ts +76 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-table v-bind="table || {}" :data="data" :header-cell-class-name="setClass" ref="elTableRef">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
<sortable-table-column-cell
|
|
5
|
+
v-if="props.modelValue"
|
|
6
|
+
v-for="v in rowValue"
|
|
7
|
+
:key="v.id"
|
|
8
|
+
:data="v"
|
|
9
|
+
/>
|
|
10
|
+
</el-table>
|
|
11
|
+
</template>
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
defineOptions({ name: 'cc-table' })
|
|
14
|
+
import { CellCls, ElTable } from 'element-plus'
|
|
15
|
+
import Sortable from 'sortablejs'
|
|
16
|
+
import { computed, onBeforeMount, onMounted, ref } from 'vue'
|
|
17
|
+
import { SortableTableIns, SortColumn } from './utils/interface'
|
|
18
|
+
import sortableTableColumnCell from './utils/sortableTableColumnCell.vue'
|
|
19
|
+
import { cloneDeep } from 'lodash'
|
|
20
|
+
let props = defineProps<SortableTableIns>()
|
|
21
|
+
const elTableRef = ref<InstanceType<typeof ElTable>>()
|
|
22
|
+
const emits = defineEmits(['update:modelValue', 'update:data'])
|
|
23
|
+
const rowValue = computed({
|
|
24
|
+
get() {
|
|
25
|
+
return props.modelValue
|
|
26
|
+
},
|
|
27
|
+
set(value) {
|
|
28
|
+
emits('update:modelValue', value)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
const data = computed({
|
|
32
|
+
get() {
|
|
33
|
+
return props.data
|
|
34
|
+
},
|
|
35
|
+
set(value) {
|
|
36
|
+
emits('update:data', value)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
onBeforeMount(() => {})
|
|
41
|
+
onMounted(() => {
|
|
42
|
+
columnDrop(elTableRef.value?.$el)
|
|
43
|
+
})
|
|
44
|
+
const columnDrop = (elem?: HTMLTableElement) => {
|
|
45
|
+
// 如果没有传入elem,则返回
|
|
46
|
+
if (!elem) return
|
|
47
|
+
// 获取表格的表头元素
|
|
48
|
+
const header = elem.querySelector('.el-table__header-wrapper')
|
|
49
|
+
// 如果没有表头元素,则返回
|
|
50
|
+
if (!header) return
|
|
51
|
+
// 设置延时执行函数
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
// 获取表头中的所有行元素
|
|
54
|
+
const trs = header.querySelectorAll('thead > tr')
|
|
55
|
+
// 遍历行元素
|
|
56
|
+
trs.forEach((v) => {
|
|
57
|
+
let tr = v as HTMLElement
|
|
58
|
+
// 创建拖拽排序对象
|
|
59
|
+
Sortable.create(tr, {
|
|
60
|
+
// 动画时间
|
|
61
|
+
animation: 180,
|
|
62
|
+
// 延迟时间
|
|
63
|
+
delay: 0,
|
|
64
|
+
// 拖拽元素
|
|
65
|
+
draggable: '.sortable',
|
|
66
|
+
// 过滤器
|
|
67
|
+
filter: (evt, item) => !getLocation(item),
|
|
68
|
+
// 拖拽排序时触发的函数
|
|
69
|
+
onMove: ({ dragged, related }) => {
|
|
70
|
+
// 获取拖拽元素的排序位置
|
|
71
|
+
let location = getLocation(dragged)
|
|
72
|
+
// 如果没有排序位置,则返回false
|
|
73
|
+
if (!location) return false
|
|
74
|
+
// 获取排序位置的数组
|
|
75
|
+
const locationArr = location.split('_').slice(1).map(Number)
|
|
76
|
+
// 判断拖拽元素是否在相关元素之前
|
|
77
|
+
return inChildren(locationArr[0], getIndex(tr, dragged), getIndex(tr, related))
|
|
78
|
+
},
|
|
79
|
+
// 拖拽排序后的函数
|
|
80
|
+
onUpdate({ oldIndex, newIndex }) {
|
|
81
|
+
// 如果没有排序值,则返回
|
|
82
|
+
if (!rowValue.value) return
|
|
83
|
+
// 如果没有旧的索引和新的索引,则返回
|
|
84
|
+
if (oldIndex === void 0 || newIndex === void 0) return
|
|
85
|
+
// 获取旧的th元素
|
|
86
|
+
let oldTh = tr.children[oldIndex]
|
|
87
|
+
// 获取新的th元素
|
|
88
|
+
let newTh = tr.children[newIndex]
|
|
89
|
+
// 获取旧的排序位置
|
|
90
|
+
let oldLocation = getLocation(oldTh)
|
|
91
|
+
// 获取新的排序位置
|
|
92
|
+
let newLocation = getLocation(newTh)
|
|
93
|
+
// 如果没有旧的排序位置或者新的排序位置,则返回false
|
|
94
|
+
if (!oldLocation || !newLocation) return false
|
|
95
|
+
// 获取旧的排序位置的数组
|
|
96
|
+
let oldLocationArr = oldLocation.split('_').slice(1).map(Number)
|
|
97
|
+
// 如果旧的排序位置的第一个元素为1,则减去count
|
|
98
|
+
if (oldLocationArr[0] === 1) {
|
|
99
|
+
let count = tr.querySelectorAll('.el-table-fixed-column--left').length
|
|
100
|
+
newIndex -= count
|
|
101
|
+
oldIndex -= count
|
|
102
|
+
}
|
|
103
|
+
// 获取新的排序位置的数组
|
|
104
|
+
let newLocationArr = newLocation.split('_').slice(1).map(Number)
|
|
105
|
+
// 获取旧的路径
|
|
106
|
+
let oldPath = getPath(oldLocationArr[0], oldIndex)
|
|
107
|
+
// 获取新的路径
|
|
108
|
+
let newPath = getPath(newLocationArr[0], newIndex)
|
|
109
|
+
// 如果没有旧的路径或者新的路径,则返回false
|
|
110
|
+
if (!oldPath || !newPath) return false
|
|
111
|
+
// 克隆排序值
|
|
112
|
+
let tem = cloneDeep(rowValue.value)
|
|
113
|
+
// 设置新的路径和新的排序值
|
|
114
|
+
setValue(cloneDeep(getValue(oldPath)), newPath, tem)
|
|
115
|
+
// 设置旧的路径和旧的排序值
|
|
116
|
+
setValue(cloneDeep(getValue(newPath)), oldPath, tem)
|
|
117
|
+
// 设置新的排序值
|
|
118
|
+
rowValue.value = tem
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
const getIndex = (father: HTMLElement, child: HTMLElement) =>
|
|
125
|
+
Array.from(father.children).indexOf(child)
|
|
126
|
+
// 获取元素的路径
|
|
127
|
+
const getLocation = (dom: Element) => dom && dom.className.match(/sortable_[0-9]+_[0-9]+/g)?.[0]
|
|
128
|
+
// 判断当前元素是否在当前行中
|
|
129
|
+
const inChildren = (level: number, from: number, to: number) => {
|
|
130
|
+
if (!rowValue.value) return false
|
|
131
|
+
if (level === 1) return true
|
|
132
|
+
let item = levelFlat(level - 1).filter((v) => !v.hide)
|
|
133
|
+
return getColumnFatherIndex(item, from) === getColumnFatherIndex(item, to)
|
|
134
|
+
}
|
|
135
|
+
// 获取当前元素的父级元素的索引
|
|
136
|
+
const getColumnFatherIndex = (item: SortColumn[], end: number) => {
|
|
137
|
+
let i = 0
|
|
138
|
+
while (end >= 0) {
|
|
139
|
+
const v = item[i]
|
|
140
|
+
i++
|
|
141
|
+
if (v.hide) continue
|
|
142
|
+
let children = v.children
|
|
143
|
+
if (!children) return false
|
|
144
|
+
end -= children.length
|
|
145
|
+
}
|
|
146
|
+
return i
|
|
147
|
+
}
|
|
148
|
+
// 获取当前元素的路径
|
|
149
|
+
const getPath = (level: number, end: number) => {
|
|
150
|
+
if (!rowValue.value) return
|
|
151
|
+
end += hideCount(level, end)
|
|
152
|
+
if (level === 1) return [end]
|
|
153
|
+
let path = Array.from({ length: level }).map((v) => 0)
|
|
154
|
+
if (!end) {
|
|
155
|
+
f(rowValue.value, 0)
|
|
156
|
+
path[level - 1] = 0
|
|
157
|
+
} else
|
|
158
|
+
while (end > 0) {
|
|
159
|
+
f(rowValue.value, 0)
|
|
160
|
+
end--
|
|
161
|
+
}
|
|
162
|
+
function f(data: SortColumn[], depth: number) {
|
|
163
|
+
let flag = 0
|
|
164
|
+
for (let i = 0; i < data.length; i++) {
|
|
165
|
+
let v = data[i]
|
|
166
|
+
if (depth === level - 1) {
|
|
167
|
+
if (flag !== i) {
|
|
168
|
+
flag = i
|
|
169
|
+
path[depth] = 0
|
|
170
|
+
}
|
|
171
|
+
path[depth] += 1
|
|
172
|
+
} else if (v.children) return f(v.children, depth + 1)
|
|
173
|
+
else path[depth] += 1
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return path
|
|
177
|
+
}
|
|
178
|
+
// 获取当前元素的值
|
|
179
|
+
const getValue = (
|
|
180
|
+
path: number[],
|
|
181
|
+
parent?: boolean,
|
|
182
|
+
data: SortColumn[] = rowValue.value
|
|
183
|
+
): SortColumn => {
|
|
184
|
+
if (!path.length) path[0] = 0
|
|
185
|
+
if (path.length <= (parent ? 2 : 1)) return data[path[0]]
|
|
186
|
+
return getValue(path.slice(1), parent, data[path[0]].children)
|
|
187
|
+
}
|
|
188
|
+
// 设置当前元素的值
|
|
189
|
+
const setValue = (data: SortColumn, path: number[], value: SortColumn[]): SortColumn[] => {
|
|
190
|
+
if (path.length) {
|
|
191
|
+
let tem = value[path[0]]
|
|
192
|
+
if (path.length === 1) value[path[0]] = data
|
|
193
|
+
else if (tem.children) value[path[0]].children = setValue(data, path.slice(1), tem.children)
|
|
194
|
+
}
|
|
195
|
+
return value
|
|
196
|
+
}
|
|
197
|
+
// 计算当前元素的隐藏数量
|
|
198
|
+
const hideCount = (level: number, index: number) =>
|
|
199
|
+
levelFlat(level)
|
|
200
|
+
.slice(0, index + 1)
|
|
201
|
+
.filter((v) => v.hide).length
|
|
202
|
+
// 获取当前行的数据
|
|
203
|
+
const levelFlat = (level: number, data = rowValue.value): SortColumn[] => {
|
|
204
|
+
if (level > 1)
|
|
205
|
+
return levelFlat(
|
|
206
|
+
level - 1,
|
|
207
|
+
data.filter((v) => v.children).flatMap((v) => v.children) as SortColumn[]
|
|
208
|
+
)
|
|
209
|
+
return data
|
|
210
|
+
}
|
|
211
|
+
// 设置当前元素的类名
|
|
212
|
+
const setClass: CellCls<typeof props.data> = ({ column }) => {
|
|
213
|
+
let className = props.table?.headerCellClassName || ''
|
|
214
|
+
if (!column.fixed && column.id) {
|
|
215
|
+
className += ` sortable sortable_${column.level}_${column.no}`
|
|
216
|
+
}
|
|
217
|
+
return className as string
|
|
218
|
+
}
|
|
219
|
+
defineExpose({ table: elTableRef })
|
|
220
|
+
</script>
|
|
221
|
+
<style scoped></style>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-dialog
|
|
3
|
+
v-model="state"
|
|
4
|
+
v-bind="config"
|
|
5
|
+
draggable
|
|
6
|
+
>
|
|
7
|
+
<div class="container">
|
|
8
|
+
<b>
|
|
9
|
+
按住
|
|
10
|
+
<el-icon><Rank /></el-icon>
|
|
11
|
+
进行移动,点击表头名字进行隐藏, 点击确定进行保存,点击
|
|
12
|
+
<!-- <Star style="width: 1em; height: 1em; margin-right: 8px" /> -->
|
|
13
|
+
<svg-icon
|
|
14
|
+
name="regular-center"
|
|
15
|
+
size="14"
|
|
16
|
+
></svg-icon>
|
|
17
|
+
固定,点击
|
|
18
|
+
<!-- <StarFilled style="width: 1em; height: 1em; margin-right: 8px" /> -->
|
|
19
|
+
<svg-icon
|
|
20
|
+
name="regular-left"
|
|
21
|
+
size="14"
|
|
22
|
+
color="#2C93FF"
|
|
23
|
+
></svg-icon>
|
|
24
|
+
或
|
|
25
|
+
<svg-icon
|
|
26
|
+
name="regular-right"
|
|
27
|
+
size="14"
|
|
28
|
+
color="#2C93FF"
|
|
29
|
+
></svg-icon>
|
|
30
|
+
取消固定
|
|
31
|
+
|
|
32
|
+
<el-popover
|
|
33
|
+
placement="bottom-start"
|
|
34
|
+
title="提示"
|
|
35
|
+
:width="200"
|
|
36
|
+
trigger="hover"
|
|
37
|
+
content="点击保存会将本表头的配置存储到数据库,下次登录还是你保存的配置,不保存的话,只在本次配置有效"
|
|
38
|
+
>
|
|
39
|
+
<template #reference>
|
|
40
|
+
<el-icon style="font-size: 14px"><QuestionFilled /></el-icon>
|
|
41
|
+
</template>
|
|
42
|
+
</el-popover>
|
|
43
|
+
</b>
|
|
44
|
+
<sortable-table-drag-item
|
|
45
|
+
style="flex-grow: 1; overflow: auto"
|
|
46
|
+
scroll-fensitivity="0"
|
|
47
|
+
v-model="modelValue"
|
|
48
|
+
show-pin
|
|
49
|
+
/>
|
|
50
|
+
|
|
51
|
+
<el-tooltip
|
|
52
|
+
content="将表头配置保存到数据库"
|
|
53
|
+
placement="top-end"
|
|
54
|
+
>
|
|
55
|
+
<el-button
|
|
56
|
+
type="primary"
|
|
57
|
+
style="width: 100%; margin-top: 10px"
|
|
58
|
+
@click="$emit('submit', modelValue)"
|
|
59
|
+
>
|
|
60
|
+
保存
|
|
61
|
+
</el-button>
|
|
62
|
+
</el-tooltip>
|
|
63
|
+
</div>
|
|
64
|
+
</el-dialog>
|
|
65
|
+
</template>
|
|
66
|
+
<script setup lang="ts">
|
|
67
|
+
import { computed, ref } from 'vue'
|
|
68
|
+
import { SortableTableDialog } from './utils/interface'
|
|
69
|
+
import sortableTableDragItem from './utils/sortableTableDragItem.vue'
|
|
70
|
+
import { Rank } from '@element-plus/icons-vue'
|
|
71
|
+
import SvgIcon from '@/components/SvgIcon.vue'
|
|
72
|
+
|
|
73
|
+
defineOptions({
|
|
74
|
+
inheritAttrs: false,
|
|
75
|
+
})
|
|
76
|
+
const emits = defineEmits(['update:modelValue', 'update:data', 'submit'])
|
|
77
|
+
const state = ref(false)
|
|
78
|
+
const props = defineProps<SortableTableDialog>()
|
|
79
|
+
const modelValue = computed({
|
|
80
|
+
get() {
|
|
81
|
+
return props.modelValue
|
|
82
|
+
},
|
|
83
|
+
set(value) {
|
|
84
|
+
emits('update:modelValue', value)
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
defineExpose({
|
|
88
|
+
open: () => {
|
|
89
|
+
state.value = true
|
|
90
|
+
},
|
|
91
|
+
close: () => {
|
|
92
|
+
state.value = false
|
|
93
|
+
},
|
|
94
|
+
state,
|
|
95
|
+
})
|
|
96
|
+
</script>
|
|
97
|
+
<style scoped lang="scss">
|
|
98
|
+
.container {
|
|
99
|
+
user-select: none;
|
|
100
|
+
-moz-user-select: none;
|
|
101
|
+
-webkit-user-select: none;
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
height: 100%;
|
|
105
|
+
> b {
|
|
106
|
+
padding-right: 20px;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SortColumn, SortColumnSend } from './interface'
|
|
2
|
+
export const setId = (data: SortColumn[]) => {
|
|
3
|
+
let i = 1
|
|
4
|
+
const idSet = new Set()
|
|
5
|
+
const _set = (id: number): number => {
|
|
6
|
+
if (idSet.has(id)) {
|
|
7
|
+
return _set(id + 1)
|
|
8
|
+
}
|
|
9
|
+
return id
|
|
10
|
+
}
|
|
11
|
+
const f = (data: SortColumn[]) => {
|
|
12
|
+
data.forEach((v) => {
|
|
13
|
+
if (v.id !== undefined && v.id !== null) return idSet.add(v.id)
|
|
14
|
+
v.id = _set(i)
|
|
15
|
+
i = v.id + 1
|
|
16
|
+
if (v.children && v.children.length) f(v.children)
|
|
17
|
+
})
|
|
18
|
+
return data
|
|
19
|
+
}
|
|
20
|
+
return f(data)
|
|
21
|
+
}
|
|
22
|
+
export const getSend = (data: SortColumn[]): SortColumnSend[] => {
|
|
23
|
+
return data.map((v) => {
|
|
24
|
+
const tem = {
|
|
25
|
+
hide: Boolean(v.hide),
|
|
26
|
+
id: v.id,
|
|
27
|
+
prop: v.col.prop,
|
|
28
|
+
title: v.col.label,
|
|
29
|
+
fixed: v.col.fixed,
|
|
30
|
+
ban: Boolean(v.ban),
|
|
31
|
+
} as SortColumnSend
|
|
32
|
+
if (v.children && v.children.length) tem.children = getSend(v.children)
|
|
33
|
+
return tem
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
export const sort = (
|
|
37
|
+
data: SortColumn[],
|
|
38
|
+
send?: SortColumnSend[],
|
|
39
|
+
): SortColumn[] => {
|
|
40
|
+
if (!send || !send.length) return data
|
|
41
|
+
const tem = [] as SortColumn[]
|
|
42
|
+
const ids: Record<number, number> = {}
|
|
43
|
+
data.forEach((v, i) => {
|
|
44
|
+
if (v.id) ids[v.id] = i
|
|
45
|
+
})
|
|
46
|
+
send.forEach((v) => {
|
|
47
|
+
const item = data.find((vv) => vv.id === v.id)
|
|
48
|
+
if (!item || !item.id) return
|
|
49
|
+
delete ids[item.id]
|
|
50
|
+
if (v.ban) return
|
|
51
|
+
item.hide = v.hide
|
|
52
|
+
item.col.fixed = v.fixed
|
|
53
|
+
if (v.children && item.children)
|
|
54
|
+
item.children = sort(item.children, v.children)
|
|
55
|
+
tem.push(item)
|
|
56
|
+
})
|
|
57
|
+
Object.keys(ids).forEach((k) => {
|
|
58
|
+
const i = ids[k]
|
|
59
|
+
const item = data.find((v) => v.id === Number(k))
|
|
60
|
+
if (!item) return
|
|
61
|
+
if (tem.length <= i) tem.push(item)
|
|
62
|
+
else tem.splice(i, 0, item)
|
|
63
|
+
})
|
|
64
|
+
return tem
|
|
65
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
export type Shortcuts = { text: string; value: Date | (() => Date) }
|
|
3
|
+
export type DefaltShortcuts = Record<ShortcutsKey, Shortcuts>
|
|
4
|
+
export type ShortcutsKey =
|
|
5
|
+
| 'today'
|
|
6
|
+
| 'tomorrow'
|
|
7
|
+
| 'yesterday'
|
|
8
|
+
| 'nextweek'
|
|
9
|
+
| 'nextmonth'
|
|
10
|
+
| 'prevmonth'
|
|
11
|
+
export const defaltShortcuts = {
|
|
12
|
+
today: {
|
|
13
|
+
text: '今天',
|
|
14
|
+
value: new Date(),
|
|
15
|
+
},
|
|
16
|
+
tomorrow: {
|
|
17
|
+
text: '明天',
|
|
18
|
+
value: () => {
|
|
19
|
+
const date = new Date()
|
|
20
|
+
date.setTime(date.getTime() + 3600 * 1000 * 24)
|
|
21
|
+
return date
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
yesterday: {
|
|
25
|
+
text: '昨天',
|
|
26
|
+
value: () => {
|
|
27
|
+
const date = new Date()
|
|
28
|
+
date.setTime(date.getTime() - 3600 * 1000 * 24)
|
|
29
|
+
return date
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
nextweek: {
|
|
33
|
+
text: '下周',
|
|
34
|
+
value: () => {
|
|
35
|
+
const date = new Date()
|
|
36
|
+
date.setTime(date.getTime() + 3600 * 1000 * 24 * 7)
|
|
37
|
+
return date
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
nextmonth: {
|
|
41
|
+
text: '下个月',
|
|
42
|
+
value: () => {
|
|
43
|
+
const date = new Date()
|
|
44
|
+
date.setTime(date.getTime() + 3600 * 1000 * 24 * 30)
|
|
45
|
+
return date
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
prevmonth: {
|
|
49
|
+
text: '上个月',
|
|
50
|
+
value: () => {
|
|
51
|
+
const date = new Date()
|
|
52
|
+
date.setTime(date.getTime() - 3600 * 1000 * 24 * 30)
|
|
53
|
+
return date
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
} as DefaltShortcuts
|
|
57
|
+
|
|
58
|
+
export const shortcuts = (keys?: ShortcutsKey[], is_ref = false) => {
|
|
59
|
+
if (!keys) {
|
|
60
|
+
if (!is_ref) return defaltShortcuts
|
|
61
|
+
return ref(defaltShortcuts)
|
|
62
|
+
} else {
|
|
63
|
+
const tem = [] as Shortcuts[]
|
|
64
|
+
keys.forEach((key) => {
|
|
65
|
+
if (defaltShortcuts[key]) {
|
|
66
|
+
tem.push(defaltShortcuts[key])
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
if (!is_ref) return tem
|
|
70
|
+
return ref(tem)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<!-- @format -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<svg
|
|
5
|
+
t="1702537913405"
|
|
6
|
+
class="icon"
|
|
7
|
+
viewBox="0 0 1024 1024"
|
|
8
|
+
version="1.1"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
p-id="1520"
|
|
11
|
+
width="14"
|
|
12
|
+
height="14"
|
|
13
|
+
>
|
|
14
|
+
<path
|
|
15
|
+
d="M0 0l204.8 409.6v512l307.2 102.4V409.6l204.8-409.6H0zM614.4 819.2h409.6v102.4h-409.6zM614.4 614.4h409.6v102.4h-409.6z"
|
|
16
|
+
:fill="color || '#b3b3b3'"
|
|
17
|
+
p-id="1521"
|
|
18
|
+
></path>
|
|
19
|
+
<path
|
|
20
|
+
d="M614.4 409.6h409.6v102.4h-409.6z"
|
|
21
|
+
:fill="color || '#b3b3b3'"
|
|
22
|
+
p-id="1522"
|
|
23
|
+
></path>
|
|
24
|
+
</svg>
|
|
25
|
+
</template>
|
|
26
|
+
<script lang="ts" setup>
|
|
27
|
+
const props = defineProps<{
|
|
28
|
+
color?: string
|
|
29
|
+
}>()
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<!-- @format -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<el-popover
|
|
5
|
+
:visible="show"
|
|
6
|
+
placement="bottom"
|
|
7
|
+
:width="width || 230"
|
|
8
|
+
:trigger="trigger"
|
|
9
|
+
@hide="emits('close')"
|
|
10
|
+
@show="emits('open')"
|
|
11
|
+
>
|
|
12
|
+
<template #reference>
|
|
13
|
+
<slot
|
|
14
|
+
name="reference"
|
|
15
|
+
:open="open"
|
|
16
|
+
:close="close"
|
|
17
|
+
:toggle="toggle"
|
|
18
|
+
/>
|
|
19
|
+
</template>
|
|
20
|
+
<div
|
|
21
|
+
style="display: flex; align-items: center; justify-content: center"
|
|
22
|
+
v-loading="loading"
|
|
23
|
+
>
|
|
24
|
+
<div style="flex-grow: 1">
|
|
25
|
+
<slot :closeF="close" />
|
|
26
|
+
</div>
|
|
27
|
+
<div style="margin-left: 5px">
|
|
28
|
+
<div>
|
|
29
|
+
<el-button
|
|
30
|
+
type="primary"
|
|
31
|
+
size="small"
|
|
32
|
+
@click="submit"
|
|
33
|
+
>
|
|
34
|
+
确认
|
|
35
|
+
</el-button>
|
|
36
|
+
</div>
|
|
37
|
+
<div style="margin-top: 5px">
|
|
38
|
+
<el-button
|
|
39
|
+
size="small"
|
|
40
|
+
@click="emits('clear')"
|
|
41
|
+
>
|
|
42
|
+
清空
|
|
43
|
+
</el-button>
|
|
44
|
+
</div>
|
|
45
|
+
<div style="margin-top: 5px">
|
|
46
|
+
<el-button
|
|
47
|
+
type="warning"
|
|
48
|
+
size="small"
|
|
49
|
+
@click="close"
|
|
50
|
+
>
|
|
51
|
+
关闭
|
|
52
|
+
</el-button>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</el-popover>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script setup lang="ts">
|
|
60
|
+
import { ref } from 'vue'
|
|
61
|
+
import { ElPopover, TooltipTriggerType } from 'element-plus'
|
|
62
|
+
const props = defineProps<{
|
|
63
|
+
width?: number
|
|
64
|
+
trigger?: TooltipTriggerType
|
|
65
|
+
loading?: boolean
|
|
66
|
+
}>()
|
|
67
|
+
const emits = defineEmits(['confirm', 'clear', 'close', 'open'])
|
|
68
|
+
const show = ref(false)
|
|
69
|
+
|
|
70
|
+
// 打开
|
|
71
|
+
const open = () => (show.value = true)
|
|
72
|
+
// 关闭
|
|
73
|
+
const close = () => {
|
|
74
|
+
show.value = false
|
|
75
|
+
}
|
|
76
|
+
const toggle = () => {
|
|
77
|
+
show.value = !show.value
|
|
78
|
+
}
|
|
79
|
+
// 面板确定按钮
|
|
80
|
+
const submit = () => {
|
|
81
|
+
emits('confirm')
|
|
82
|
+
close()
|
|
83
|
+
}
|
|
84
|
+
defineExpose({
|
|
85
|
+
open,
|
|
86
|
+
close,
|
|
87
|
+
toggle,
|
|
88
|
+
submit,
|
|
89
|
+
})
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<style scoped lang="scss"></style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// GlobalComponents for Volar
|
|
2
|
+
declare module '@vue/runtime-core' {
|
|
3
|
+
export interface GlobalComponents {
|
|
4
|
+
'sortable-table': (typeof import('../sortableTable.vue'))['default']
|
|
5
|
+
'sortable-table-dialog': (typeof import('../sortableTableDialog.vue'))['default']
|
|
6
|
+
'sortable-table-column-cell': (typeof import('./sortableTableColumnCell.vue'))['default']
|
|
7
|
+
'sortable-table-drag-item': (typeof import('./sortableTableDragItem.vue'))['default']
|
|
8
|
+
'header-popover': (typeof import('./headerPopover.vue'))['default']
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export {}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ColumnCls, TableColumnInstance, TableInstance } from 'element-plus'
|
|
2
|
+
import ElDialog from 'element-plus/es/components/dialog'
|
|
3
|
+
import { Component, Ref, h } from 'vue'
|
|
4
|
+
export interface Scope<T> {
|
|
5
|
+
row: T
|
|
6
|
+
$index: number
|
|
7
|
+
column: ColumnCls<T>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type Mutable<T> = {
|
|
11
|
+
-readonly [P in keyof T]: T[P]
|
|
12
|
+
}
|
|
13
|
+
export type Props<T> = Mutable<
|
|
14
|
+
Partial<Omit<T, `$${string}` | `_${string}` | '$' | '_'>>
|
|
15
|
+
>
|
|
16
|
+
export type anyObj = { [key: string | number | symbol]: any }
|
|
17
|
+
export interface SortColumn {
|
|
18
|
+
hide?: boolean
|
|
19
|
+
ban?: boolean
|
|
20
|
+
id?: number
|
|
21
|
+
key?: string
|
|
22
|
+
col: Props<TableColumnInstance>
|
|
23
|
+
scope?(props: any): string
|
|
24
|
+
component?: (createVNode: typeof h, data: Scope<any>) => Component
|
|
25
|
+
header?: (
|
|
26
|
+
createVNode: typeof h,
|
|
27
|
+
data: Pick<Scope<any>, '$index' | 'column'>,
|
|
28
|
+
) => Component
|
|
29
|
+
children?: SortColumn[]
|
|
30
|
+
}
|
|
31
|
+
export type SortColumnSend = Pick<SortColumn, 'id' | 'hide'> & {
|
|
32
|
+
children?: SortColumnSend[]
|
|
33
|
+
fixed: TableColumnInstance['fixed']
|
|
34
|
+
ban: boolean
|
|
35
|
+
}
|
|
36
|
+
export interface SortableTableIns
|
|
37
|
+
extends /* @vue-ignore */ Omit<
|
|
38
|
+
Props<TableInstance>,
|
|
39
|
+
'data' | 'ref' | 'headerCellClassName'
|
|
40
|
+
> {
|
|
41
|
+
table?: /* @vue-ignore */
|
|
42
|
+
Props<TableInstance> | /* @vue-ignore */ Ref<Props<TableInstance>>['value']
|
|
43
|
+
modelValue: SortColumn[] | Ref<SortColumn[]>['value']
|
|
44
|
+
data: anyObj[] | Ref<anyObj[]>['value']
|
|
45
|
+
noMove?: boolean
|
|
46
|
+
}
|
|
47
|
+
export interface SortableTableDialog {
|
|
48
|
+
config?: /* @vue-ignore */
|
|
49
|
+
| Props<InstanceType<typeof ElDialog>>
|
|
50
|
+
| /* @vue-ignore */ Ref<Props<InstanceType<typeof ElDialog>>>['value']
|
|
51
|
+
modelValue: SortColumn[] | Ref<SortColumn[]>['value']
|
|
52
|
+
}
|