@xuekl/cli-components 1.0.0 → 1.0.2

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.
@@ -0,0 +1,117 @@
1
+ <template>
2
+ <div class="my_menu" :style="{ left: position.x + 'px', top: position.y + 'px' }">
3
+ <div class="menu_item" v-for="item in menus" :key="item.value" @click.stop="resultSend(item)">
4
+ <span style="width: 100%;display: flex;justify-content: space-between;"
5
+ :class="{ 'menu-disabled': item.disabled }">{{ item.label }}<span v-if="item.children?.length">
6
+ <icon-svg name="more"></icon-svg>
7
+ </span></span>
8
+ <div class="my_sub_menu">
9
+ <div class="menu_item" v-for="sub in item.children" :key="sub.value" @click.stop="resultSend(sub)">
10
+ <span class="menu_name" :class="{ 'menu-disabled': item.disabled }">{{ sub.label }}</span>
11
+ </div>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </template>
16
+ <script lang="ts">
17
+ export default {
18
+ name: 'ContextMenu'
19
+ }
20
+ </script>
21
+ <script setup lang="ts">
22
+ import { LocalMenu } from '@/utils/type'
23
+ import { Ref, ref } from 'vue';
24
+ const props = defineProps(['position', 'type'])
25
+ const emit = defineEmits(['result'])
26
+ const { position, type } = props
27
+
28
+ const newChildren: LocalMenu[] = []
29
+ if (type === 'folder' || type === 'root') {
30
+ newChildren.unshift({
31
+ value: 'folder', label: '目录'
32
+ }, {
33
+ value: 'page', label: '菜单'
34
+ })
35
+ } else {
36
+ newChildren.unshift(
37
+ { value: 'entity', label: '实体' },
38
+ { value: 'dialogEdit', label: '弹窗' },
39
+ { value: 'subEidt', label: '页面' },
40
+ { value: 'dialogDetail', label: '弹窗(详情)' },
41
+ { value: 'subDetail', label: '页面(详情)' },)
42
+ }
43
+
44
+ const menus: Ref<LocalMenu[]> = ref([
45
+ {
46
+ value: 'new',
47
+ label: '新建',
48
+ children: newChildren
49
+ },
50
+ { value: 'cut', label: '剪切', disabled: true },
51
+ { value: 'copy', label: '复制', disabled: true },
52
+ { value: 'paste', label: '粘贴', disabled: true },
53
+ { value: 'rename', label: '重命名', disabled: type === 'root' },
54
+ { value: 'delete', label: '删除', disabled: type === 'root' },
55
+ ])
56
+
57
+ const resultSend = (item: LocalMenu) => {
58
+ if (item.children || item.disabled) {
59
+ return false
60
+ }
61
+ emit('result', item)
62
+ }
63
+ </script>
64
+ <style lang="scss" scoped>
65
+ .my_menu {
66
+ position: fixed;
67
+ z-index: 1000;
68
+ display: flex;
69
+ flex-direction: column;
70
+ background-color: #000;
71
+ color: #fff;
72
+ border-radius: 4px;
73
+ box-shadow: 2px 2px 2px 2px #f5f5ff;
74
+
75
+ .menu_item {
76
+ width: 110px;
77
+ height: 40px;
78
+ display: flex;
79
+ align-items: center;
80
+ padding: 0 10px;
81
+ cursor: pointer;
82
+
83
+ .menu_name {
84
+ display: inline-block;
85
+ width: 100%;
86
+ white-space: nowrap;
87
+ overflow: hidden;
88
+ text-overflow: ellipsis;
89
+ }
90
+
91
+ &:hover {
92
+ background-color: #333;
93
+
94
+ .my_sub_menu {
95
+ display: block;
96
+ }
97
+ }
98
+ }
99
+
100
+ .my_sub_menu {
101
+ display: none;
102
+ background-color: #000;
103
+ color: #fff;
104
+ border-radius: 4px;
105
+ box-shadow: 2px 2px 2px 2px #f5f5ff;
106
+ position: absolute;
107
+ left: 100%;
108
+ top: 0;
109
+ border-left: 1px solid #f5f5f5;
110
+ }
111
+
112
+ .menu-disabled {
113
+ color: #aaa;
114
+ cursor: not-allowed;
115
+ }
116
+ }
117
+ </style>
package/PaddingBox.vue ADDED
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <div class="padding-box">
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+ <script lang="ts">
7
+ import { Vue, Options } from "vue-class-component";
8
+
9
+ @Options({
10
+ name: 'PaddingBox'
11
+ })
12
+ export default class PaddingBox extends Vue { }
13
+ </script>
14
+
15
+ <style lang="scss" scoped>
16
+ .padding-box {
17
+ padding-bottom: 22px;
18
+ }
19
+ </style>
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="queryVisible" class="page-query" :class="['mb-' + gutters]">
4
+ <slot name="query"></slot>
5
+ </div>
6
+ <div class="page-body">
7
+ <slot></slot>
8
+ </div>
9
+ <div v-if="footerVisible" class="page-footer" :class="['mt-' + gutters]">
10
+ <slot name="footer"></slot>
11
+ </div>
12
+ </div>
13
+ </template>
14
+ <script lang="ts">
15
+ import { Vue, Options } from 'vue-class-component'
16
+
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
+ }
32
+ }
33
+ })
34
+ export default class PageContainer extends Vue {
35
+ gutters: unknown
36
+ queryVisible: unknown
37
+ footerVisible: unknown
38
+ }
39
+ </script>
40
+ <style lang="scss" scoped>
41
+ .page-query {
42
+ padding: 20px;
43
+ background-color: #fff;
44
+ }
45
+
46
+ .page-body {
47
+ padding: 20px;
48
+ background-color: #fff;
49
+ }
50
+
51
+ .page-footer {
52
+ display: flex;
53
+ justify-content: flex-end;
54
+ padding: 20px;
55
+ background-color: #fff;
56
+ }
57
+ </style>
package/XklButton.vue ADDED
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <real-el-button v-if="isAuth(auth)" @click.prevent="btnClick">
3
+ <slot></slot>
4
+ </real-el-button>
5
+ </template>
6
+ <script lang="ts">
7
+ export default {
8
+ name: 'ElButton'
9
+ }
10
+ </script>
11
+ <script setup lang="ts">
12
+ import { ElButton as RealElButton } from 'element-plus'
13
+ import { componentGlobal } from '@/utils/global'
14
+ import { isAuth } from '@/utils'
15
+ const props = defineProps(['auth'])
16
+ const emit = defineEmits(['click', 'async'])
17
+
18
+ const { auth } = props
19
+ let preventClick = false
20
+
21
+ const btnClick = () => {
22
+ emit('click')
23
+ if (componentGlobal.enableSubmit) {
24
+ preventClick = false
25
+ componentGlobal.enableSubmit = false
26
+ }
27
+ if (!preventClick) {
28
+ preventClick = true
29
+ emit('async', () => {
30
+ setTimeout(() => preventClick = false, 200)
31
+ })
32
+ }
33
+ }
34
+ </script>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <el-date-picker :type="type" :start-placeholder="startPlaceholder" :end-placeholder="endPlaceholder"
3
+ :value-format="valueFormat" />
4
+ </template>
5
+ <script lang="ts">
6
+ export default {
7
+ name: 'XklDatePicker'
8
+ }
9
+ </script>
10
+ <script setup lang="ts">
11
+ import { ref } from 'vue';
12
+
13
+ const props = defineProps(['type'])
14
+ const { type } = props
15
+
16
+ console.log('type', type);
17
+
18
+
19
+ const startPlaceholder = ref('')
20
+ const endPlaceholder = ref('')
21
+ const valueFormat = ref('YYYY-MM-DD')
22
+ if (type === 'daterange') {
23
+ startPlaceholder.value = '开始日期'
24
+ endPlaceholder.value = '结束日期'
25
+ valueFormat.value = 'YYYY-MM-DD'
26
+ } else if (type === 'datetimerange') {
27
+ startPlaceholder.value = '开始时间'
28
+ endPlaceholder.value = '结束时间'
29
+ valueFormat.value = 'YYYY-MM-DD HH:mm:ss'
30
+ }
31
+
32
+ </script>
package/XklDict.vue CHANGED
@@ -1,15 +1,30 @@
1
1
  <template>
2
2
  <el-select style="width: 100%;">
3
- <el-option v-for="item in list" :key="item.id" :label="item.dicValue" :value="item.dicKey"></el-option>
3
+ <el-option v-for="item in dataList" :key="item.dictCode" :label="item.dictLabel"
4
+ :value="item.dictValue"></el-option>
4
5
  </el-select>
5
6
  </template>
7
+ <script lang="ts">
8
+ export default {
9
+ name: 'XklDict'
10
+ }
11
+ </script>
6
12
  <script setup lang="ts">
7
- import storeController from '@/controller/common/store.controller';
8
- import { defineProps, reactive } from 'vue'
9
- const props = defineProps(['dict'])
10
- const { dict } = reactive(props)
11
- const { dictList } = storeController
13
+ import { ref, onBeforeMount, Ref } from 'vue'
14
+ import http from "@/utils/httpRequest"
15
+ const props = defineProps(['config'])
16
+ const { config } = props
17
+ const dataList: Ref<{ dictCode: string, dictLabel: string, dictValue: string | number }[]> = ref([])
12
18
 
13
- const list = dictList.filter(res => res.type === dict)
14
- console.log(list)
19
+ onBeforeMount(() => {
20
+ http({
21
+ url: http.adornUrl(`system/dict/data/type/${config.dict}`),
22
+ method: 'get',
23
+ params: http.adornParams({})
24
+ }).then(({ data }) => {
25
+ if (data.code === 200) {
26
+ dataList.value = data.data
27
+ }
28
+ })
29
+ })
15
30
  </script>
package/XklForm.vue CHANGED
@@ -1,133 +1,200 @@
1
1
  <template>
2
- <el-form ref="xklForm" :model="form" :label-width="config.labelWidth">
3
- <el-row :gutter="20">
4
- <template v-for="item in formList" :key="item.key">
5
- <el-col v-if="item.show()" :span="item.span || config.span">
6
- <el-form-item :label="item.label" :label-width="item.labelWidth" :rules="item.rules" :prop="item.key">
7
- <slot v-if="item.slot" :name="item.key"></slot>
8
- <div v-else style="width: 100%;display: flex;">
9
- <XklDict v-if="item.dict" v-model="form[item.key]" clearable :placeholder="item.placeholder"
10
- :dict="item.dict" :disabled="item.disabled()"></XklDict>
11
- <XklSelect v-else-if="item.url || item.list" v-model="form[item.key]"
12
- :placeholder="item.placeholder" :config="item" clearable :disabled="item.disabled()">
13
- </XklSelect>
14
- <el-checkbox-group v-else-if="item.boxes" v-model="form[item.key]">
15
- <el-checkbox v-for="box in item.boxes" :label="box.value" :key="box.value">{{ box.label
16
- }}</el-checkbox>
17
- </el-checkbox-group>
18
- <el-radio-group v-else-if="item.radios" v-model="form[item.key]">
19
- <el-radio v-for="rad in item.radios" :label="rad.value" :key="rad.value">{{ rad.label
20
- }}</el-radio>
21
- </el-radio-group>
22
- <el-input type="textarea" v-else-if="item.rows" v-model="form[item.key]"
23
- :placeholder="item.placeholder" :disabled="item.disabled()" :rows="item.rows"
24
- :autosize="item.autosize" :maxlength="item.maxlength" :minlength="item.minlength"
25
- :show-word-limit="item.showWordLimit"></el-input>
26
- <el-input v-else v-model="form[item.key]" :placeholder="item.placeholder"
27
- :disabled="item.disabled()" :maxlength="item.maxlength" :minlength="item.minlength"
28
- :show-word-limit="item.showWordLimit"></el-input>
29
- </div>
2
+ <el-form ref="XklFormRef" :model="form" :label-width="opts.labelWidth">
3
+ <el-row>
4
+ <template v-for="item in formList" :key="item.prop">
5
+ <el-col :span="item.span" v-if="item.show()">
6
+ <el-form-item :label="item.label" :label-width="item.labelWidth" :prop="item.prop"
7
+ :rules="item.refRules.value">
8
+ <el-input v-if="item.type === 'input'" v-model="form[item.prop]" v-bind="item.element"
9
+ v-on="item.events" :disabled="item.disabled()"></el-input>
10
+ <el-input-number v-else-if="item.type === 'input-number'" v-model="form[item.prop]"
11
+ v-bind="item.element" v-on="item.events" :disabled="item.disabled()"
12
+ style="width: 100%;"></el-input-number>
13
+ <el-input v-else-if="item.type === 'textarea'" v-model="form[item.prop]" v-bind="item.element"
14
+ :disabled="item.disabled()" v-on="item.events" type="textarea"></el-input>
15
+ <XklSelect v-else-if="item.type === 'select'" v-model="form[item.prop]"
16
+ v-model:label="form[item.prop + 'Label']" :list="item.list" :config="{}" v-bind="item.element"
17
+ v-on="item.events" :disabled="item.disabled()">
18
+ </XklSelect>
19
+ <XklDict v-else-if="item.type === 'dict-select'" v-model="form[item.prop]"
20
+ v-model:label="form[item.prop + 'Label']" :config="item.config" v-bind="item.element"
21
+ v-on="item.events" :disabled="item.disabled()"></XklDict>
22
+ <XklSelect v-else-if="item.type === 'url-select'" v-model="form[item.prop]"
23
+ v-model:label="form[item.prop + 'Label']" :config="item.config" v-bind="item.element"
24
+ v-on="item.events" :disabled="item.disabled()">
25
+ </XklSelect>
26
+ <XklTreeSelect v-else-if="item.type === 'tree-select'" v-model="form[item.prop]"
27
+ :config="item.config" v-bind="item.element" v-on="item.events" :disabled="item.disabled()">
28
+ </XklTreeSelect>
29
+ <el-radio-group v-else-if="item.type === 'radio'" v-model="form[item.prop]" v-bind="item.element"
30
+ v-on="item.events" :disabled="item.disabled()">
31
+ <el-radio v-for="ra in item.list" :label="ra.value" :key="ra.value">{{ ra.label }}</el-radio>
32
+ </el-radio-group>
33
+ <el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="form[item.prop]"
34
+ v-bind="item.element" v-on="item.events" :disabled="item.disabled()">
35
+ <el-checkbox v-for="ch in item.list" :label="ch.value" :key="ch.value">{{ ch.label
36
+ }}</el-checkbox>
37
+ </el-checkbox-group>
38
+ <XklDatePicker v-else-if="item.type === 'date-picker'" v-model="form[item.prop]"
39
+ v-bind="item.element" v-on="item.events" style="width: 100%;"></XklDatePicker>
40
+ <XklUpload v-else-if="item.type === 'upload'" :key="form[item.prop].length > 0"
41
+ v-model="form[item.prop]" :config="item.config" v-bind="item.element" v-on="item.events">
42
+ </XklUpload>
43
+ <slot v-else :name="item.prop"></slot>
30
44
  </el-form-item>
31
45
  </el-col>
32
46
  </template>
33
- <el-col :span="config.span">
34
- <slot name="_action"></slot>
47
+ <el-col :span="searchSpan">
48
+ <el-form-item label-width="0">
49
+ <div class="query-action">
50
+ <slot name="_action"></slot>
51
+ </div>
52
+ </el-form-item>
35
53
  </el-col>
36
54
  </el-row>
37
55
  </el-form>
38
56
  </template>
39
-
57
+ <script lang="ts">
58
+ export default {
59
+ name: "XklForm",
60
+ components: { XklTreeSelect, XklDict, XklDatePicker }
61
+ }
62
+ </script>
40
63
  <script setup lang="ts">
41
- import { Ref, defineProps, onMounted, reactive, ref, watch } from 'vue'
42
- import { setUpperFirst } from '@/utils'
43
- import XklSelect from './XklSelect.vue';
64
+ import { setUpperFirst } from '@xuekl/cli-utils'
65
+ import { FormItem } from '@/utils/type'
66
+ import { ref, watch, onMounted } from 'vue'
67
+ import XklSelect from './XklSelect.vue'
68
+ import XklTreeSelect from './XklTreeSelect.vue'
44
69
  import XklDict from './XklDict.vue'
45
- import { RuleItem } from 'async-validator';
70
+ import XklDatePicker from './XklDatePicker.vue'
46
71
 
47
72
  const props = defineProps(['form'])
48
- const { form } = reactive(props)
49
-
50
- const formList: Ref = ref([])
51
-
52
- const config = form.getConfig()
53
- const options = form.getOptions()
54
- const xklForm: Ref = ref(null)
55
-
56
- Object.keys(form).forEach(key => {
57
- const upperKey = setUpperFirst(key)
58
- if (form['get' + upperKey]) {
59
- const item = form['get' + upperKey]()
60
-
61
- const placelabel = item.label.replace(':', '').replace(':', '').trim()
62
- if (item.dict || item.url || item.list) {
63
- item.placeholder = item.placeholder || '请选择' + placelabel
64
- } else {
65
- item.placeholder = item.placeholder || '请输入' + placelabel
66
- }
73
+ const XklFormRef = ref(null)
74
+ const { form } = props
75
+ const formList: FormItem[] = []
76
+ const opts = form._opts || {}
67
77
 
68
- item.required = item.required || (() => false)
69
- item.show = item.show || (() => true)
70
- item.disabled = item.disabled || (() => false)
71
-
72
- if (options.mode === 'search') {
73
- item.rules = ref([])
74
- if (item.mode === 'search') {
75
- formList.value.push({
76
- key: key,
77
- ...item
78
+ // 获取符合mode的字段
79
+ const modeFields: any = {}
80
+ Object.keys(form).forEach(prop => {
81
+ if (form['get' + setUpperFirst(prop)]) {
82
+ const field: FormItem = form['get' + setUpperFirst(prop)]()
83
+ field.rules = field.rules || []
84
+ field.refRules = ref(field.rules)
85
+ field.show = field.show || (() => true)
86
+ field.disabled = field.disabled || (() => false)
87
+ if (!['query', 'search'].includes(opts.mode)) {
88
+ if (field.required) {
89
+ // 如果穿了required函数监听required的变化
90
+ watch(field.required, (val) => {
91
+ if (val) {
92
+ field.refRules.value.push({ required: true, message: '请输入' + field.label, trigger: 'blur' })
93
+ } else {
94
+ field.refRules.value = field.refRules.value.filter(res => !res.required)
95
+ }
78
96
  })
79
97
  }
98
+ field.required = field.required || (() => false)
99
+ if (field.required()) {
100
+ field.refRules.value.push({ required: true, message: '请输入' + field.label, trigger: 'blur' })
101
+ }
80
102
  } else {
81
- if (item.rules) {
82
- item.rules = ref(item.rules)
83
- } else {
84
- item.rules = ref([])
103
+ field.refRules.value = field.refRules.value.filter(res => !res.required)
104
+ }
105
+ const placeholderStart = ['input', 'textarea'].includes(field.type) ? '请输入' : '请选择'
106
+ if (!field.element) {
107
+ field.element = {
108
+ placeholder: placeholderStart + field.label.replace(':', '').replace(':', ''),
109
+ clearable: true
85
110
  }
86
-
87
- if (item.required()) {
88
- item.rules.value.push({ required: true, message: '请输入' + placelabel, trigger: 'blur' })
111
+ } else {
112
+ field.element.placeholder = placeholderStart + field.label.replace(':', '').replace(':', '')
113
+ field.element.clearable = typeof field.element.clearable === 'undefined' ? true : field.element.clearable
114
+ }
115
+ const item = {
116
+ prop,
117
+ type: field.type,
118
+ label: field.label,
119
+ span: field.span || opts.span,
120
+ labelWidth: field.labelWidth || opts.labelWidth,
121
+ show: field.show,
122
+ disabled: field.disabled,
123
+ required: field.required,
124
+ refRules: field.refRules,
125
+ element: field.element,
126
+ events: field.events || {},
127
+ list: field.list,
128
+ config: field.config || {}
129
+ }
130
+ if (opts.mode) {
131
+ if (field.mode && field.mode.includes(opts.mode)) {
132
+ formList.push(item)
89
133
  }
90
-
91
- watch(item.required, (newVal) => {
92
- if (newVal) {
93
- item.rules.value.push({ required: true, message: '请输入' + placelabel, trigger: 'blur' })
94
- } else {
95
- item.rules.value = item.rules.value.filter((item: RuleItem) => !item.required)
96
- xklForm.value.clearValidate([key])
97
- }
98
- })
99
- formList.value.push({
100
- key: key,
101
- ...item
102
- })
134
+ } else {
135
+ formList.push(item)
103
136
  }
137
+ }
138
+ })
104
139
 
140
+ //计算按钮所占span
141
+ let toalSpan = 0
142
+ const searchSpan = ref(0)
143
+ formList.forEach(res => {
144
+ if (res.show && res.show()) {
145
+ if (res.span) {
146
+ toalSpan = toalSpan + res.span
147
+ } else {
148
+ toalSpan = toalSpan + opts.span
149
+ }
105
150
  }
106
151
 
107
- const regProto = () => {
108
- let enableSubmit = true
109
- form.setSubmit((call: (fn: () => void) => void) => {
152
+ })
153
+ searchSpan.value = 24 - toalSpan % 24
154
+
155
+
156
+ const regProto = () => {
157
+ if (XklFormRef.value) {
158
+ let enableSubmit = true;
159
+ form.setSubmit((callback: (call: () => void, feils: any) => void) => {
110
160
  if (enableSubmit) {
111
- enableSubmit = false
112
- xklForm.value.validate((valid: boolean) => {
161
+ enableSubmit = false;
162
+ formList.forEach(field => {
163
+ modeFields[field.prop] = (form as any)[field.prop]
164
+ });
165
+ (XklFormRef.value as any).validate((valid: boolean) => {
113
166
  if (valid) {
114
- call(() => {
167
+ callback(() => {
115
168
  setTimeout(() => {
116
169
  enableSubmit = true
117
170
  }, 300)
118
- })
171
+ }, modeFields)
119
172
  } else {
120
173
  enableSubmit = true
121
174
  }
122
175
  })
123
176
  }
124
- })
125
- form.setResetFields(xklForm.value.resetFields)
177
+ }, form)
126
178
  }
127
179
 
128
- onMounted(() => {
129
- regProto()
130
- })
180
+ form.setBinds(() => {
181
+ formList.forEach(field => {
182
+ modeFields[field.prop] = (form as any)[field.prop]
183
+ });
184
+ return modeFields
185
+ }, form)
186
+ }
187
+
188
+ onMounted(() => {
189
+ regProto()
131
190
  })
132
191
 
133
- </script>
192
+
193
+
194
+ </script>
195
+ <style lang="scss" scoped>
196
+ .query-action {
197
+ width: 100%;
198
+ text-align: right;
199
+ }
200
+ </style>
package/XklLink.vue ADDED
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <real-el-link v-if="isAuth(auth)" @click.prevent="btnClick">
3
+ <slot></slot>
4
+ </real-el-link>
5
+ </template>
6
+ <script lang="ts">
7
+ export default {
8
+ name: 'ElLink'
9
+ }
10
+ </script>
11
+ <script setup lang="ts">
12
+ import { ElLink as RealElLink } from 'element-plus'
13
+ import { componentGlobal } from '@/utils/global'
14
+ import { isAuth } from '@/utils'
15
+ const props = defineProps(['auth'])
16
+ const emit = defineEmits(['click', 'async'])
17
+
18
+ const { auth } = props
19
+ let preventClick = false
20
+
21
+ const btnClick = () => {
22
+ emit('click')
23
+ if (componentGlobal.enableSubmit) {
24
+ preventClick = false
25
+ componentGlobal.enableSubmit = false
26
+ }
27
+ if (!preventClick) {
28
+ preventClick = true
29
+ emit('async', () => {
30
+ setTimeout(() => preventClick = false, 200)
31
+ })
32
+ }
33
+ }
34
+ </script>
package/XklSelect.vue CHANGED
@@ -1,28 +1,66 @@
1
1
  <template>
2
- <el-select style="width: 100%;">
3
- <el-option v-for="item in dataList" :key="item.key" :label="item[config.labelTarget] || item.label"
4
- :value="item[config.valueTarget] || item.value"></el-option>
2
+ <el-select style="width: 100%;" @change="changeHandle">
3
+ <el-option v-for="item in dataList" :key="item.id" :label="item.label" :value="item.value"></el-option>
5
4
  </el-select>
6
5
  </template>
6
+ <script lang="ts">
7
+ export default {
8
+ name: 'XklSelect'
9
+ }
10
+ </script>
7
11
  <script setup lang="ts">
8
- import { Ref, defineProps, reactive, ref } from 'vue';
9
- import http from '@/utils/httpRequest'
10
- const props = defineProps(['config'])
12
+ import { onBeforeMount, ref, Ref, watch } from 'vue'
13
+ import { SelectItem } from '@/utils/type'
14
+ import http from "@/utils/httpRequest"
15
+ const props = defineProps(['config', 'list'])
16
+ const emit = defineEmits(['update:label'])
17
+ const { config, list } = props
18
+
19
+ const dataList: Ref<SelectItem[]> = ref([])
11
20
 
12
- const { config } = reactive(props)
21
+ const changeHandle = (val: string) => {
22
+ const item = dataList.value.find(res => res.value === val)
23
+ if (item) {
24
+ emit('update:label', item.label)
25
+ }
26
+ }
13
27
 
14
- const dataList: Ref = ref([])
28
+ const handleData = (data) => {
29
+ data.forEach(inner => {
30
+ inner.value = inner[config?.valueTarget || 'value']
31
+ inner.label = inner[config?.labelTarget || 'label']
32
+ })
33
+ return data
34
+ }
15
35
 
16
- if (config.list) {
17
- dataList.value = config.list
18
- } else if (config.url) {
19
- http({
20
- url: http.adornUrl(config.url),
21
- method: 'get',
22
- params: http.adornParams({})
23
- }).then(({ data }) => {
24
- dataList.value = data.data
36
+ if (typeof list === 'function') {
37
+ watch(list, (val: SelectItem[]) => {
38
+ dataList.value = val
25
39
  })
26
40
  }
27
41
 
28
- </script>
42
+ onBeforeMount(() => {
43
+ if (list) {
44
+ if (typeof list === 'function') {
45
+ return false
46
+ }
47
+ dataList.value = handleData(list)
48
+ } else {
49
+ if (!config) { return }
50
+ http({
51
+ url: http.adornUrl(config.url),
52
+ method: 'get',
53
+ params: http.adornParams(config.params)
54
+ }).then(({ data }) => {
55
+ dataList.value = handleData(data.data)
56
+ })
57
+ }
58
+ })
59
+ </script>
60
+ <style lang="scss">
61
+ .readony-input {
62
+ .el-input__inner {
63
+ cursor: not-allowed;
64
+ }
65
+ }
66
+ </style>
package/XklTable.vue CHANGED
@@ -1,9 +1,30 @@
1
1
  <template>
2
- <el-table :data="table.list" style="width: 100%">
3
- <el-table-column v-if="table.selection" type="selection"></el-table-column>
4
- <el-table-column v-for="item in columns" :key="item.prop" :prop="item.prop" :label="item.label"
5
- :width="item.width"></el-table-column>
6
- <el-table-column fixed="right" :label="operation.label">
2
+ <el-table ref="XklTable" :data="table.list" style="width: 100%" :header-cell-style="{ background: '#F1F4F9' }">
3
+ <el-table-column v-if="table.selection" type="selection" align="center"></el-table-column>
4
+ <el-table-column v-if="table.index" type="index" align="center" v-bind="table.indexConfig"></el-table-column>
5
+ <el-table-column v-for="item in table.columns" :key="item.prop" :prop="item.prop" :label="item.label"
6
+ :width="item.width" :align="item.align || 'center'" :sortable="item.sortable">
7
+ <template v-if="item.reflect" v-slot="{ row }">
8
+ {{ row[item.reflect] }}
9
+ </template>
10
+ <template v-if="item.dict" v-slot="{ row }">
11
+ <el-tag v-if="item.tags"
12
+ :style="{ backgroundColor: tagColor(item, row) + '22', borderColor: tagColor(item, row) + '22', color: tagColor(item, row) }">
13
+ {{ dictLabel(item, row) }}
14
+ </el-tag>
15
+ <span v-else>{{ dictLabel(item, row) }}</span>
16
+ </template>
17
+ <template v-else-if="item.tags" v-slot="{ row }">
18
+ <el-tag
19
+ :style="{ backgroundColor: tagColor(item, row) + '22', borderColor: tagColor(item, row) + '22', color: tagColor(item, row) }">
20
+ {{ row[item.prop] }}
21
+ </el-tag>
22
+ </template>
23
+ <template v-else-if="item.slot" v-slot="{ row }">
24
+ <slot :name="item.prop" :row="row"></slot>
25
+ </template>
26
+ </el-table-column>
27
+ <el-table-column v-if="table.operation.operation !== false" align="center" v-bind="table.operation">
7
28
  <template #default="{ row }">
8
29
  <slot name="_operation" :row="row"></slot>
9
30
  </template>
@@ -13,13 +34,53 @@
13
34
  </template>
14
35
  </el-table>
15
36
  </template>
37
+ <script lang="ts">
38
+ export default {
39
+ name: 'XklTable'
40
+ }
41
+ </script>
16
42
  <script setup lang="ts">
17
- import { TableColumn, TableOperation } from '@xuekl/cli-base/types';
18
- import { defineProps, reactive } from 'vue'
43
+ import http from "@/utils/httpRequest"
44
+ import { computed } from "vue";
19
45
  const props = defineProps(['table'])
20
- const { table } = reactive(props)
46
+ const { table } = props
47
+ const dictTypes = table.columns.map(res => res.dict).filter(res => !!res)
48
+ const dictStore = {}
49
+
50
+ dictTypes.forEach((dict: string) => {
51
+ http({
52
+ url: http.adornUrl(`system/dict/data/type/${dict}`),
53
+ method: 'get',
54
+ params: http.adornParams({})
55
+ }).then(({ data }) => {
56
+ if (data.code === 200) {
57
+ dictStore[dict] = data.data
58
+ }
59
+ })
60
+ })
61
+
62
+ const dictLabel = computed(() => {
63
+ return function (col: any, row: any) {
64
+ if (dictStore[col.dict]) {
65
+ const item = dictStore[col.dict].find(res => res.dictValue == row[col.prop]) || {}
66
+ return item.dictLabel
67
+ }
68
+ return ''
69
+ }
70
+ })
21
71
 
22
- const columns: TableColumn[] = table.columns
23
- const operation: TableOperation = table.operation
72
+ const tagColor = computed(() => {
73
+ return function (col, row) {
74
+ if (col.tags) {
75
+ if (Array.isArray(col.tags)) {
76
+ const item = col.tags.find(res => res.value == row[col.prop]) || {}
77
+ return item.color
78
+ } else {
79
+ return col.tags.color
80
+ }
81
+ }
82
+ return ''
83
+ }
84
+ })
24
85
 
25
86
  </script>
package/XklTree.vue ADDED
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <el-tree :props="props" :load="loadNode" lazy show-checkbox @check-change="handleCheckChange" />
3
+ </template>
4
+ <script lang="ts">
5
+ export default {
6
+ name: 'XklTree'
7
+ }
8
+ </script>
9
+ <script setup lang="ts">
10
+ const props = {
11
+ label: 'name',
12
+ children: 'zones',
13
+ }
14
+
15
+ const loadNode = () => { }
16
+ const handleCheckChange = () => { }
17
+ </script>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <el-tree-select style="width: 100%;" :data="dataList" />
3
+ </template>
4
+ <script lang="ts">
5
+ export default {
6
+ name: 'XklTreeSelect'
7
+ }
8
+ </script>
9
+ <script setup lang="ts">
10
+ import { onBeforeMount, ref } from 'vue'
11
+ import http from "@/utils/httpRequest";
12
+ import { treeData } from '@/utils'
13
+ const props = defineProps(['config'])
14
+ const { config } = props
15
+
16
+ const dataList: any = ref([])
17
+
18
+ const handleData = (data) => {
19
+ data.forEach(inner => {
20
+ inner.value = inner[config.valueTarget || 'value']
21
+ inner.label = inner[config.labelTarget || 'label']
22
+ if (inner.children) {
23
+ handleData(inner.children)
24
+ }
25
+ })
26
+ return data
27
+ }
28
+
29
+ onBeforeMount(() => {
30
+ http({
31
+ url: http.adornUrl(config.url),
32
+ method: 'get',
33
+ params: http.adornParams(config.params)
34
+ }).then(({ data }) => {
35
+ if (data.code === 200) {
36
+ if (config.toTree) {
37
+ data.data = treeData(data.data, config.toTree.id, config.toTree.pId)
38
+ if (config.toTree.incorporate) {
39
+ dataList.value = [{ value: 0, label: config.toTree.incorporate, children: handleData(data.data) }]
40
+ } else {
41
+ dataList.value = handleData(data.data)
42
+ }
43
+ } else {
44
+ dataList.value = handleData(data.data)
45
+ }
46
+ }
47
+ })
48
+ })
49
+
50
+ </script>
package/XklUpload.vue ADDED
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <el-upload v-model:file-list="fileList" class="upload-demo" :headers="headers" :action="actionUrl"
3
+ :on-change="handleChange" :before-upload="beforeUpload">
4
+ <el-button type="primary">点击上传</el-button>
5
+ <template #tip>
6
+ <div v-if="config.maxSize" class="el-upload__tip">
7
+ 文件大小不得超过{{ config.maxSize }}M
8
+ </div>
9
+ </template>
10
+ </el-upload>
11
+ </template>
12
+ <script lang="ts">
13
+ export default {
14
+ name: 'XklUpload'
15
+ }
16
+ </script>
17
+ <script setup lang="ts">
18
+ import { ref, onMounted } from 'vue'
19
+ import { ElMessage } from 'element-plus'
20
+ import http from '@/utils/httpRequest';
21
+ import { getToken } from '@/utils'
22
+ const props = defineProps(['config', 'modelValue'])
23
+ const emit = defineEmits(['update:modelValue'])
24
+ const { config, modelValue } = props
25
+
26
+ const headers = {
27
+ Authorization: getToken()
28
+ }
29
+ const actionUrl = http.adornUrl(config.url || '/common/upload')
30
+
31
+ const fileList = ref([])
32
+
33
+ const beforeUpload = (file) => {
34
+ if (config.maxSize) {
35
+ if (file.size > config.maxSize * 1024 * 1024) {
36
+ ElMessage.warning(`文件大小不得超过${config.maxSize}M`)
37
+ return false
38
+ }
39
+ }
40
+ return true
41
+ }
42
+ const handleChange = (_file, _files) => {
43
+ const upFiles = fileList.value.map((res: any) => {
44
+ const j = {
45
+ name: res.name,
46
+ url: res.url
47
+ }
48
+ if (res.response) {
49
+ j.name = res.response.originalFilename
50
+ j.url = res.response.url
51
+ }
52
+
53
+ return j
54
+ })
55
+ emit('update:modelValue', upFiles)
56
+ }
57
+
58
+
59
+ onMounted(() => {
60
+ fileList.value = modelValue
61
+ })
62
+ </script>
package/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ import ContextMenu from './ContextMenu.vue'
2
+ import PaddingBox from './PaddingBox.vue'
3
+ import PageContainer from './PageContainer.vue'
4
+ import XklButton from './XklButton.vue'
5
+ import XklDatePicker from './XklDatePicker.vue'
6
+ import XklDict from './XklDict.vue'
7
+ import XklForm from './XklForm.vue'
8
+ import XklLink from './XklLink.vue'
9
+ import XklSelect from './XklSelect.vue'
10
+ import XklTable from './XklTable.vue'
11
+ import XklTree from './XklTree.vue'
12
+ import XklTreeSelect from './XklTreeSelect.vue'
13
+ import XklUpload from './XklUpload.vue'
14
+
15
+ export {
16
+ ContextMenu,
17
+ PaddingBox,
18
+ PageContainer,
19
+ XklButton,
20
+ XklDatePicker,
21
+ XklDict,
22
+ XklForm,
23
+ XklLink,
24
+ XklSelect,
25
+ XklTable,
26
+ XklTree,
27
+ XklTreeSelect,
28
+ XklUpload,
29
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@xuekl/cli-components",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
- "main": "index.js",
5
+ "main": "index.ts",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
8
8
  },