@xuekl/cli-components 1.6.1 → 1.9.145

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/PageContainer.vue CHANGED
@@ -1,57 +1,92 @@
1
1
  <template>
2
2
  <div class="page-container">
3
- <div v-if="queryVisible" class="page-query" :class="['mb-' + gutters]">
3
+ <div v-if="queryVisible" class="page-query part-bg" :class="['mb-' + gutters, 'pd-' + padding]">
4
4
  <slot name="query"></slot>
5
5
  </div>
6
- <div class="page-body">
6
+ <div v-for="upper in upperSlots" :key="upper" class="page-upper part-bg"
7
+ :class="['mb-' + gutters, 'pd-' + padding]">
8
+ <slot :name="upper"></slot>
9
+ </div>
10
+ <div class="page-body part-bg" :class="['pd-' + padding]">
7
11
  <slot></slot>
8
12
  </div>
9
- <div v-if="footerVisible" class="page-footer" :class="['mt-' + gutters]">
13
+ <div v-for="down in downSlots" class="page-down part-bg" :class="['mt-' + gutters, 'pd-' + padding]">
14
+ <slot :name="down"></slot>
15
+ </div>
16
+ <div v-if="footerVisible" class="page-footer part-bg"
17
+ :class="['mt-' + gutters, 'pd-' + padding, { 'footer-fixed': footerFixed }]">
10
18
  <slot name="footer"></slot>
11
19
  </div>
20
+ <div v-if="footerFixed" :style="{ height: footerHeight + 'px' }"></div>
12
21
  </div>
13
22
  </template>
14
23
  <script lang="ts">
15
- import { Vue, Options } from 'vue-class-component'
24
+ export default {
25
+ name: 'PageContainer'
26
+ }
27
+ </script>
28
+ <script lang="ts" setup>
29
+ import { onMounted, ref } from 'vue'
30
+ const props = defineProps({
31
+ gutters: {
32
+ type: Number,
33
+ default: 2
34
+ },
35
+ queryVisible: {
36
+ type: Boolean,
37
+ default: true
38
+ },
39
+ footerVisible: {
40
+ type: Boolean,
41
+ default: true
42
+ },
43
+ footerFixed: {
44
+ type: Boolean
45
+ },
46
+ upperSlots: {
47
+ type: Array,
48
+ default: []
49
+ },
50
+ downSlots: {
51
+ type: Array,
52
+ default: []
53
+ },
54
+ padding: {
55
+ type: Number,
56
+ default: 20
57
+ }
58
+ })
59
+ const { gutters, queryVisible, footerVisible, footerFixed, upperSlots, downSlots, padding } = props
60
+
61
+ const footerHeight = ref(0)
62
+ onMounted(() => {
63
+ if (footerFixed) {
64
+ const height = document.querySelector('.page-footer')?.clientHeight || 0
16
65
 
17
- @Options({
18
- name: "PageContainer",
19
- props: {
20
- gutters: {
21
- type: Number,
22
- default: 2
23
- },
24
- queryVisible: {
25
- type: Boolean,
26
- default: true
27
- },
28
- footerVisible: {
29
- type: Boolean,
30
- default: true
31
- }
66
+ footerHeight.value = height
32
67
  }
33
68
  })
34
- export default class PageContainer extends Vue {
35
- gutters: unknown
36
- queryVisible: unknown
37
- footerVisible: unknown
38
- }
39
69
  </script>
40
70
  <style lang="scss" scoped>
41
- .page-query {
42
- padding: 20px;
43
- background-color: #fff;
71
+ .page-container {
72
+ position: relative;
73
+ z-index: 1;
44
74
  }
45
75
 
46
- .page-body {
47
- padding: 20px;
48
- background-color: #fff;
76
+ .part-bg {
77
+ background-color: rgba(255, 255, 255, .65);
49
78
  }
50
79
 
51
80
  .page-footer {
52
81
  display: flex;
53
82
  justify-content: flex-end;
54
- padding: 20px;
55
- background-color: #fff;
83
+ }
84
+
85
+ .footer-fixed {
86
+ position: fixed;
87
+ left: 0;
88
+ bottom: 0;
89
+ width: 100%;
90
+ z-index: 999;
56
91
  }
57
92
  </style>
package/XklButton.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <real-el-button v-if="isAuth(auth)" @click.prevent="btnClick">
2
+ <real-el-button v-if="doAuth(auth)" @click.prevent="btnClick">
3
3
  <slot></slot>
4
4
  </real-el-button>
5
5
  </template>
@@ -10,35 +10,66 @@ export default {
10
10
  </script>
11
11
  <script setup lang="ts">
12
12
  import { ElButton as RealElButton } from 'element-plus'
13
- import { componentGlobal } from '@xuekl/cli-base/global'
14
13
  import { isAuth } from '@/utils'
15
- import { useAttrs } from 'vue'
14
+ import { ref, useAttrs } from 'vue'
16
15
  import { ElMessageBox } from 'element-plus'
16
+ import { useRoute } from 'vue-router'
17
+ const startLoading = window.startLoading
18
+ const finishLoading = window.finishLoading
19
+ const props = defineProps(['auth', 'prevent', 'openType', 'name', 'mask'])
20
+ const route: any = useRoute()
17
21
 
18
- const props = defineProps(['auth', 'prevent'])
19
- const emit = defineEmits(['click', 'async'])
22
+ const { auth, name } = props
20
23
 
21
- const { auth } = props
24
+ const mask = typeof props.mask === 'undefined' ? true : props.mask
22
25
 
23
- const attrs = useAttrs()
24
- let preventClick = false
26
+ const doAuth = (auth) => {
27
+ if (name) {
28
+ return isAuth(route?.name + ':' + name)
29
+ } else {
30
+ return isAuth(auth)
31
+ }
32
+ }
33
+
34
+
35
+ const attrs: any = useAttrs()
36
+ const preventClick = ref(false)
25
37
 
26
38
  const btnClick = () => {
27
- emit('click')
28
- if (componentGlobal.enableSubmit) {
29
- preventClick = false
30
- componentGlobal.enableSubmit = false
39
+ if (attrs.click) {
40
+ attrs.onClick()
41
+ if (props.openType) {
42
+ window[props.openType] && window[props.openType]()
43
+ }
31
44
  }
32
- if (!preventClick) {
33
- preventClick = true
34
- emit('async', () => {
35
- setTimeout(() => preventClick = false, 200)
36
- })
45
+
46
+ if (attrs.onAsync) {
47
+ if (!preventClick.value) {
48
+ preventClick.value = true
49
+ if (props.openType !== 'preventLoading' && startLoading) {
50
+ startLoading()
51
+ }
52
+ attrs.onAsync(() => {
53
+ setTimeout(() => {
54
+ preventClick.value = false;
55
+ if (finishLoading) {
56
+ finishLoading()
57
+ }
58
+ if (props.openType) {
59
+ window[props.openType] && window[props.openType]()
60
+ }
61
+ }, 200)
62
+ })
63
+ }
64
+
37
65
  }
38
66
 
39
67
  if (attrs.onConfirm) {
40
68
  if (props.prevent === false) {
41
69
  attrs.onConfirm()
70
+ if (props.openType) {
71
+ window[props.openType] && window[props.openType]()
72
+ }
42
73
  } else {
43
74
  ElMessageBox.confirm(
44
75
  '当前内容可能存在修改,确认继续?',
@@ -50,9 +81,36 @@ const btnClick = () => {
50
81
  }
51
82
  ).then(() => {
52
83
  attrs.onConfirm()
84
+ if (props.openType) {
85
+ window[props.openType] && window[props.openType]()
86
+ }
53
87
  }).catch(() => {
54
88
  })
55
89
  }
90
+ } else {
91
+ if (props.openType) {
92
+ window[props.openType] && window[props.openType]()
93
+ }
94
+ }
95
+ }
96
+ </script>
97
+
98
+ <style lang="scss" scoped>
99
+ .loading-mask {
100
+ position: absolute;
101
+ left: 0;
102
+ top: 0;
103
+ bottom: 0;
104
+ right: 0;
105
+ background-color: rgba(0, 0, 0, 0.6);
106
+ z-index: 1003;
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+
111
+ .is-loading {
112
+ font-size: 40px;
113
+ color: #fff;
56
114
  }
57
115
  }
58
- </script>
116
+ </style>
package/XklDatePicker.vue CHANGED
@@ -1,6 +1,13 @@
1
1
  <template>
2
- <el-date-picker :type="type" :start-placeholder="startPlaceholder" :end-placeholder="endPlaceholder"
3
- :value-format="valueFormat" />
2
+ <div v-if="type === 'doubledatetime'" class="doubledatetime">
3
+ <el-date-picker type="datetime" v-model="startVal" placeholder="开始时间"
4
+ :value-format="valueFormat"></el-date-picker>
5
+ <el-date-picker type="datetime" v-model="endVal" placeholder="结束时间"
6
+ :value-format="valueFormat"></el-date-picker>
7
+ </div>
8
+ <el-date-picker v-else :type="type" v-model="modelVal" :start-placeholder="startPlaceholder"
9
+ :popper-class="func === 'bottomshortcut' ? 'bottomshortcut' : ''" :end-placeholder="endPlaceholder"
10
+ :value-format="valueFormat" :shortcuts="shortcuts" />
4
11
  </template>
5
12
  <script lang="ts">
6
13
  export default {
@@ -8,11 +15,39 @@ export default {
8
15
  }
9
16
  </script>
10
17
  <script setup lang="ts">
11
- import { ref } from 'vue';
18
+ import { ref, computed, Ref } from 'vue';
19
+ import moment from 'dayjs'
12
20
 
13
- const props = defineProps(['type'])
14
- const { type } = props
21
+ const props = defineProps(['type', 'func', 'modelValue'])
22
+ const emit = defineEmits(['update:modelValue'])
23
+ const { type, func } = props
15
24
 
25
+ const modelVal = computed({
26
+ get() {
27
+ return props.modelValue
28
+ },
29
+ set(val) {
30
+ emit('update:modelValue', val)
31
+ }
32
+ })
33
+
34
+ const startVal = computed({
35
+ get() {
36
+ return props.modelValue[0]
37
+ },
38
+ set(val) {
39
+ emit('update:modelValue', [val, props.modelValue[1]])
40
+ }
41
+ })
42
+
43
+ const endVal = computed({
44
+ get() {
45
+ return props.modelValue[1]
46
+ },
47
+ set(val) {
48
+ emit('update:modelValue', [props.modelValue[0], val])
49
+ }
50
+ })
16
51
 
17
52
  const startPlaceholder = ref('')
18
53
  const endPlaceholder = ref('')
@@ -27,7 +62,7 @@ if (type === 'daterange') {
27
62
 
28
63
  if (['date', 'dates', 'daterange'].includes(type)) {
29
64
  valueFormat.value = 'YYYY-MM-DD'
30
- } else if (['datetime', 'datetimerange'].includes(type)) {
65
+ } else if (['datetime', 'datetimerange', 'doubledatetime'].includes(type)) {
31
66
  valueFormat.value = 'YYYY-MM-DD HH:mm:ss'
32
67
  } else if (['month', 'monthrange'].includes(type)) {
33
68
  valueFormat.value = 'YYYY-MM'
@@ -35,4 +70,77 @@ if (['date', 'dates', 'daterange'].includes(type)) {
35
70
  valueFormat.value = ''
36
71
  }
37
72
 
38
- </script>
73
+ const shortcuts: Ref<any[]> = ref([])
74
+
75
+ if (func === 'bottomshortcut') {
76
+ shortcuts.value = [{
77
+ text: '此刻',
78
+ value: () => {
79
+ if (props.modelValue && props.modelValue.length) {
80
+ if (props.modelValue[0] > moment().format('YYYY-MM-DD HH:mm:ss')) {
81
+ modelVal.value = [moment().format('YYYY-MM-DD 00:00:00'), moment().format('YYYY-MM-DD HH:mm:ss')]
82
+ } else {
83
+ modelVal.value = [props.modelValue[0], moment().format('YYYY-MM-DD HH:mm:ss')]
84
+ }
85
+
86
+ } else {
87
+ modelVal.value = [moment().format('YYYY-MM-DD 00:00:00'), moment().format('YYYY-MM-DD HH:mm:ss')]
88
+ }
89
+ }
90
+ },
91
+ {
92
+ text: '今天',
93
+ value: () => {
94
+ modelVal.value = [moment().format('YYYY-MM-DD 00:00:00'), moment().format('YYYY-MM-DD 23:59:59')]
95
+ }
96
+ }]
97
+ }
98
+
99
+ </script>
100
+ <style lang="scss">
101
+ .doubledatetime {
102
+ display: flex;
103
+
104
+ box-shadow: 0 0 0 0.01rem var(--el-input-border-color, var(--el-border-color)) inset;
105
+ border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
106
+ padding: 1px;
107
+
108
+ .el-input {
109
+ border: 0;
110
+
111
+ height: 0.3rem;
112
+
113
+ // .el-input__prefix {
114
+ // display: none;
115
+ // }
116
+
117
+ .el-input__wrapper {
118
+ box-shadow: none;
119
+ }
120
+ }
121
+ }
122
+
123
+ .bottomshortcut {
124
+ .el-picker-panel__sidebar {
125
+ z-index: 1;
126
+ bottom: -35px;
127
+ top: unset;
128
+ right: 150px;
129
+ display: flex;
130
+ justify-content: flex-end;
131
+ padding-top: 0;
132
+ }
133
+
134
+ .el-picker-panel__shortcut {
135
+ width: auto;
136
+ padding-right: 24px;
137
+ padding-left: 0;
138
+ font-size: 12px;
139
+ white-space: nowrap;
140
+ }
141
+
142
+ .el-picker-panel__body {
143
+ margin-left: 0;
144
+ }
145
+ }
146
+ </style>
package/XklDict.vue CHANGED
@@ -1,6 +1,13 @@
1
1
  <template>
2
- <el-select style="width: 100%;" @change="changeHandle">
3
- <el-option v-for="item in dataList" :key="item.dictValue" :label="item.dictLabel"
2
+ <div v-if="fakeRender && (!selectData || (selectData && !selectData.length))" class="fake-render el-input__wrapper"
3
+ :class="{ 'el-select__wrapper is-disabled': disabled || readonly }" @click="updateRender">
4
+ <span class="fs-14">{{ $attrs.placeholder
5
+ }}</span>
6
+ </div>
7
+ <el-select v-else style="width: 100%;" ref="XklDictRef" v-model="selectData" :automatic-dropdown="true"
8
+ :class="{ 'readony-input': readonly }" @change="changeHandle" :filterable="initFilterable"
9
+ :disabled="disabled || readonly" :filter-method="filterMethod">
10
+ <el-option v-for="item in list" :key="item.dictValue" :label="item.dictLabel"
4
11
  :value="item.dictValue"></el-option>
5
12
  </el-select>
6
13
  </template>
@@ -10,30 +17,108 @@ export default {
10
17
  }
11
18
  </script>
12
19
  <script setup lang="ts">
13
- import { ref, onBeforeMount, Ref } from 'vue'
14
- import http from "@/utils/httpRequest"
15
- import { baseConf } from './index'
16
- const props = defineProps(['config'])
17
- const emit = defineEmits(['update:label', 'loaded'])
18
-
19
- const { config } = props
20
- const dataList: Ref<{ dictCode: string, dictLabel: string, dictValue: string | number }[]> = ref([])
21
-
22
- const changeHandle = (val: string) => {
23
- const item = dataList.value.find(res => res.dictValue === val)
24
- if (item) {
25
- emit('update:label', item.dictLabel)
20
+ import { ref, onBeforeMount, Ref, computed, onBeforeUnmount } from 'vue'
21
+ import { baseConf, dictConf } from './index'
22
+ import DictStore from '@/utils/DictStore'
23
+ import { nextTick } from 'vue';
24
+ interface DictItem {
25
+ dictCode: string, dictLabel: string, dictValue: string | number
26
+ }
27
+ const props = defineProps(['config', 'filterable', 'readonly', 'disabled', 'modelValue', 'fake'])
28
+ const emit = defineEmits(['update:label', 'itemChange', 'loaded', 'update:modelValue'])
29
+
30
+ const { config, filterable, readonly, fake } = props
31
+ const list: Ref<DictItem[]> = ref([])
32
+
33
+ const isFake = typeof fake === 'undefined' ? true : fake
34
+ const fakeRender = ref(isFake)
35
+ const XklDictRef: any = ref(null)
36
+
37
+ const updateRender = () => {
38
+ fakeRender.value = false
39
+ nextTick(() => {
40
+ XklDictRef.value.focus()
41
+ })
42
+ }
43
+
44
+ const initFilterable = ref(false)
45
+
46
+ initFilterable.value = typeof filterable !== 'undefined' ? filterable : dictConf?.filterable
47
+
48
+ const disabled = computed(() => props.disabled)
49
+ let sourceData: DictItem[] = []
50
+
51
+ const selectData = computed({
52
+ get() {
53
+ return props.modelValue
54
+ },
55
+ set(val) {
56
+
57
+ emit('update:modelValue', val)
58
+ }
59
+ })
60
+
61
+ const filterMethod = (val: any) => {
62
+ if (val) {
63
+ val = val.trim()
64
+ list.value = sourceData.filter(res => res.dictValue.toString().includes(val) || res.dictLabel.includes(val))
65
+ } else {
66
+ list.value = sourceData
26
67
  }
27
68
  }
28
69
 
29
- onBeforeMount(() => {
30
- http({
31
- url: http.adornUrl(`${baseConf.dict_api_url}${config.dict}`),
32
- method: 'get',
33
- params: http.adornParams({})
34
- }).then(({ data }) => {
35
- dataList.value = data.data
36
- emit('loaded', dataList.value)
70
+ const changeHandle = (val: string | number | string[] | number[]) => {
71
+ if (Array.isArray(val)) {
72
+ const values: (string | number)[] = val
73
+ const items = sourceData.filter(res => values.includes(res.dictValue))
74
+ const labels = items.map(res => res.dictLabel)
75
+ if (items) {
76
+ emit('update:label', labels)
77
+ emit('itemChange', items)
78
+ }
79
+ } else {
80
+ const item = sourceData.find(res => res.dictValue === val)
81
+ if (item) {
82
+ emit('update:label', item.dictLabel)
83
+ emit('itemChange', item)
84
+ }
85
+ }
86
+ }
87
+
88
+ onBeforeMount(async () => {
89
+ list.value = await DictStore.getDict(config.dict)
90
+ sourceData = JSON.parse(JSON.stringify(list.value))
91
+ emit('loaded', list.value, (vals) => {
92
+ list.value = vals
93
+ sourceData = JSON.parse(JSON.stringify(list.value))
37
94
  })
38
95
  })
39
- </script>
96
+
97
+ onBeforeUnmount(() => {
98
+ list.value = []
99
+ sourceData = []
100
+ })
101
+ </script>
102
+ <style lang="scss">
103
+ .readony-input {
104
+ .is-disabled .el-input__wrapper {
105
+ background-color: #fff !important;
106
+
107
+ .el-input__inner {
108
+ color: #606266;
109
+ -webkit-text-fill-color: #606266;
110
+ }
111
+ }
112
+ }
113
+
114
+ .fake-render {
115
+ width: 100%;
116
+ justify-content: flex-start;
117
+ color: #a8abb2;
118
+ height: 32px;
119
+ }
120
+
121
+ .el-select__wrapper.is-disabled {
122
+ border: 1px solid #dcdfe6;
123
+ }
124
+ </style>
@@ -0,0 +1,111 @@
1
+ <template>
2
+ <real-el-dropdown-item v-if="doAuth(auth)" @click.stop="btnClick">
3
+ <slot></slot>
4
+ </real-el-dropdown-item>
5
+ </template>
6
+ <script lang="ts">
7
+ export default {
8
+ name: 'ElDropdownItem'
9
+ }
10
+ </script>
11
+ <script setup lang="ts">
12
+ import { ElMessageBox, ElDropdownItem as RealElDropdownItem } from 'element-plus'
13
+ import { Loading } from "@element-plus/icons-vue";
14
+ import { useAttrs, ref } from 'vue'
15
+ import { isAuth } from '@/utils'
16
+ import { useRoute } from 'vue-router'
17
+ const startLoading = window.startLoading
18
+ const finishLoading = window.finishLoading
19
+ const props = defineProps(['auth', 'prevent', 'openType', 'name', 'mask'])
20
+ const route: any = useRoute()
21
+
22
+ const { auth, name } = props
23
+ const mask = typeof props.mask === 'undefined' ? true : props.mask
24
+ const doAuth = (auth) => {
25
+ if (name) {
26
+ return isAuth(route.name + ':' + name)
27
+ } else {
28
+ return isAuth(auth)
29
+ }
30
+ }
31
+
32
+ const attrs: any = useAttrs()
33
+ const preventClick = ref(false)
34
+
35
+ const btnClick = () => {
36
+ if (attrs.click) {
37
+ attrs.onClick()
38
+ if (props.openType) {
39
+ window[props.openType] && window[props.openType]()
40
+ }
41
+ }
42
+
43
+ if (attrs.onAsync) {
44
+ if (!preventClick.value) {
45
+ preventClick.value = true
46
+ if (props.openType !== 'preventLoading' && startLoading) {
47
+ startLoading()
48
+ }
49
+ attrs.onAsync(() => {
50
+ setTimeout(() => {
51
+ preventClick.value = false;
52
+ if (finishLoading) {
53
+ finishLoading()
54
+ }
55
+ if (props.openType) {
56
+ window[props.openType] && window[props.openType]()
57
+ }
58
+ }, 200)
59
+ })
60
+ }
61
+ }
62
+
63
+ if (attrs.onConfirm) {
64
+ if (props.prevent === false) {
65
+ attrs.onConfirm()
66
+ if (props.openType) {
67
+ window[props.openType] && window[props.openType]()
68
+ }
69
+ } else {
70
+ ElMessageBox.confirm(
71
+ '当前内容可能存在修改,确认继续?',
72
+ '提示',
73
+ {
74
+ confirmButtonText: '确认',
75
+ cancelButtonText: '取消',
76
+ type: 'warning',
77
+ }
78
+ ).then(() => {
79
+ attrs.onConfirm()
80
+ if (props.openType) {
81
+ window[props.openType] && window[props.openType]()
82
+ }
83
+ }).catch(() => {
84
+ })
85
+ }
86
+ } else {
87
+ if (props.openType) {
88
+ window[props.openType] && window[props.openType]()
89
+ }
90
+ }
91
+ }
92
+ </script>
93
+ <style lang="scss" scoped>
94
+ .loading-mask {
95
+ position: absolute;
96
+ left: 0;
97
+ top: 0;
98
+ bottom: 0;
99
+ right: 0;
100
+ background-color: rgba(0, 0, 0, 0.6);
101
+ z-index: 1003;
102
+ display: flex;
103
+ align-items: center;
104
+ justify-content: center;
105
+
106
+ .is-loading {
107
+ font-size: 40px;
108
+ color: #fff;
109
+ }
110
+ }
111
+ </style>