vue-2024-ui 0.0.8 → 0.0.10

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.form.md CHANGED
@@ -131,8 +131,8 @@
131
131
  ``` javascript
132
132
 
133
133
  <script setup>
134
- import { ref ,reactive} from "vue";
135
- const formData=reactive({
134
+ import { ref} from "vue";
135
+ const formData=ref({
136
136
  form:{
137
137
  submit: { hidden: false },
138
138
  reset: { hidden: false },
package/README.md CHANGED
@@ -36,8 +36,8 @@ app.mount('#app')
36
36
 
37
37
  ``` javascript
38
38
  <script setup>
39
- import { reactive } from "vue";
40
- const formData = reactive({
39
+ import { ref } from "vue";
40
+ const formData = ref({
41
41
  id: { label: "ID", type: "number", value: 1, disabled: true, edit: false },
42
42
  name: {
43
43
  label: "姓名", value: "张三", width: 100,
@@ -215,7 +215,7 @@ const edit = (row, c, i, m) => {
215
215
  }
216
216
  const read = (row, c, i, m) => {
217
217
  }
218
- formData.table = {
218
+ formData.value.table = {
219
219
  border: undefined,
220
220
  page: { pageSize: 10, style: { justifyContent: 'flex-end' }, onChange: (a, b) => console.log(a, b) }
221
221
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-2024-ui",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "src/components/index.js",
@@ -37,7 +37,8 @@
37
37
  </slot>
38
38
  </el-checkbox-group>
39
39
  <!--select-->
40
- <el-select v-model="ctrlValue" v-bind="selectModel" v-else-if="ctrlType == 'select'">
40
+ <el-select v-model="ctrlValue" :placeholder="itemInfo.label" v-bind="selectModel"
41
+ v-else-if="ctrlType == 'select'">
41
42
  <template #default v-if="itemInfo?.options?.some(a => a.options)">
42
43
  <slot :name="`${ctrlKey}-ctrl`" :options="itemInfo.options">
43
44
  <el-option-group v-for="group in itemInfo.options" :label="group.label">
@@ -61,24 +62,28 @@
61
62
  </template>
62
63
  </el-select>
63
64
  <!--tree-select-->
64
- <el-tree-select v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'tree-select'">
65
+ <el-tree-select v-model="ctrlValue" :placeholder="itemInfo.label" v-bind="itemInfo"
66
+ v-else-if="ctrlType == 'tree-select'">
65
67
  <template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
66
68
  <slot :name="`${ctrlKey}-ctrl-${slot}`" :data></slot>
67
69
  </template>
68
70
  </el-tree-select>
69
71
  <!--time-->
70
- <el-time-picker v-model="ctrlValue" arrow-control v-bind="itemInfo" v-else-if="ctrlType == 'time'" />
72
+ <el-time-picker v-model="ctrlValue" arrow-control v-bind="itemInfo" :placeholder="itemInfo.label"
73
+ v-else-if="ctrlType == 'time'" />
71
74
  <!--time-select-->
72
- <el-time-select v-model="ctrlValue" start="06:30" step="00:15" end="23:30" v-bind="itemInfo"
73
- v-else-if="ctrlType == 'time-select'" />
75
+ <el-time-select v-model="ctrlValue" start="06:30" step="00:15" end="23:30" :placeholder="itemInfo.label"
76
+ v-bind="itemInfo" v-else-if="ctrlType == 'time-select'" />
74
77
  <!--date-->
75
- <el-date-picker v-model="ctrlValue" type="date" v-bind="itemInfo" v-else-if="ctrlType == 'date'">
78
+ <el-date-picker v-model="ctrlValue" type="date" :placeholder="itemInfo.label" v-bind="itemInfo"
79
+ v-else-if="ctrlType == 'date'">
76
80
  <template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
77
81
  <slot :name="`${ctrlKey}-ctrl-${slot}`" :data></slot>
78
82
  </template>
79
83
  </el-date-picker>
80
84
  <!--datetime-->
81
- <el-date-picker v-model="ctrlValue" type="datetime" v-bind="itemInfo" v-else-if="ctrlType == 'datetime'">
85
+ <el-date-picker v-model="ctrlValue" type="datetime" :placeholder="itemInfo.label" v-bind="itemInfo"
86
+ v-else-if="ctrlType == 'datetime'">
82
87
  <template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
83
88
  <slot :name="`${ctrlKey}-ctrl-${slot}`" :data></slot>
84
89
  </template>
@@ -114,20 +119,21 @@
114
119
  </template>
115
120
  </el-upload>
116
121
  <!--autocomplete-->
117
- <el-autocomplete v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'autocomplete'">
122
+ <el-autocomplete v-model="ctrlValue" v-bind="itemInfo" :placeholder="itemInfo.label"
123
+ v-else-if="ctrlType == 'autocomplete'">
118
124
  <template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
119
125
  <slot :name="`${ctrlKey}-ctrl-${slot}`" :data></slot>
120
126
  </template>
121
127
  </el-autocomplete>
122
128
  <!--input-number-->
123
- <el-input-number v-model="ctrlValue" :min="0" :max="100000000" v-bind="itemInfo"
129
+ <el-input-number v-model="ctrlValue" :min="0" :max="100000000" :placeholder="itemInfo.label" v-bind="itemInfo"
124
130
  v-else-if="ctrlType == 'input-number'">
125
131
  <template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
126
132
  <slot :name="`${ctrlKey}-ctrl-${slot}`" :data></slot>
127
133
  </template>
128
134
  </el-input-number>
129
135
  <!--input-->
130
- <el-input v-model="ctrlValue" show-word-limit :maxlength="itemInfo.max || 25" :clearable="true"
136
+ <el-input v-model="ctrlValue" :placeholder="itemInfo.label" :maxlength="itemInfo.max || 25" :clearable="true"
131
137
  v-bind="itemInfo" v-else>
132
138
  <template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
133
139
  <slot :name="`${ctrlKey}-ctrl-${slot}`" :data></slot>
@@ -139,8 +145,10 @@
139
145
  <script setup>
140
146
  defineOptions({ inheritAttrs: false });
141
147
  import { onMounted, useAttrs, useSlots } from "vue";
148
+ import { filterObject } from ".";
142
149
  const ctrlValue = defineModel({ required: true });
143
- const itemInfo = useAttrs().item;
150
+ const itemInfo = filterObject(useAttrs().item, k => k != 'value');
151
+ delete itemInfo.formatter;
144
152
  const ctrlKey = useAttrs().ctrlKey;
145
153
  const ctrlType = itemInfo.type;
146
154
  const model = useAttrs().model;
@@ -1,5 +1,7 @@
1
1
  <template>
2
- <el-form ref="gform" :model="model" v-bind="model.form" class="g-form-container">
2
+ <el-form ref="gform" :model="model"
3
+ v-bind="filterObject(model.form, k => !['columns', 'footer', 'submit', 'reset', 'slots', 'type', 'sort'].includes(k))"
4
+ class="g-form-container">
3
5
  <slot>
4
6
  <el-form-item :label="item.label" :prop="`${key}.value`" :rules="getItemRulesByItem(item)"
5
7
  v-for="(item, key) of items" :key="key" v-bind="{ ...model?.formItems, ...item?.formItem }"
@@ -18,11 +20,13 @@
18
20
  <slot name="footer" v-if="!model.form.footer.hidden">
19
21
  <div :style="model.form.footer.style">
20
22
  <slot name="footer-left"></slot>
21
- <el-button @click="model.form.submit.click(model)" v-bind="model.form.submit"
23
+ <el-button @click.stop="model.form.submit.click(formInfo, model)"
24
+ v-bind="filterObject(model.form.submit, k => !['click'].includes(k))"
22
25
  v-if="!model?.form?.submit?.hidden">
23
26
  {{ model?.form?.submit?.label }}
24
27
  </el-button>
25
- <el-button @click="model.form.reset.click(model)" v-bind="model.form.reset"
28
+ <el-button @click="model.form.reset.click(model)"
29
+ v-bind="filterObject(model.form.reset, k => !['click'].includes(k))"
26
30
  v-if="!model?.form?.reset?.hidden">{{
27
31
  model?.form?.reset?.label
28
32
  }}</el-button>
@@ -34,15 +38,15 @@
34
38
  </template>
35
39
 
36
40
  <script setup>
37
- import { computed, inject, onMounted, ref, useAttrs, watch, watchEffect } from "vue";
41
+ import { computed, getCurrentInstance, inject, onBeforeUnmount, onMounted, ref, useAttrs, watch } from "vue";
38
42
  import gCtrl from "./g-ctrl.vue";
39
- import { convertToPx, mergeObjects } from "./index";
43
+ import { convertToPx, mergeObjects, filterObject } from "./index";
40
44
  defineOptions({
41
45
  name: "g-form",
42
46
  inheritAttrs: false
43
47
  })
44
48
  const model = defineModel({ required: true });
45
- const emits = defineEmits(["submit", "reset"]);
49
+ const emits = defineEmits(["handSubmit", "reset"]);
46
50
  const gform = ref(null);
47
51
  let marginRight = ref(32);
48
52
  const options = inject('options');
@@ -73,13 +77,14 @@ const defaultFormAttrs = {
73
77
  label: "提交",
74
78
  plain: true,
75
79
  hidden: false,
76
- click: async (model) => {
80
+ click: async (formInfo, model) => {
77
81
  if (!gform.value) return
78
82
  await gform.value.validate((valid, fields) => {
79
83
  if (valid) {
80
- emits("submit", formInfo.value, model);
84
+ emits("handSubmit", formInfo, model);
85
+ console.log("提交");
81
86
  } else {
82
- console.log('error submit!', fields);
87
+ console.log('表单验证不通过!', fields);
83
88
  }
84
89
  })
85
90
  },
@@ -101,6 +106,7 @@ const defaultFormAttrs = {
101
106
  }
102
107
  },
103
108
  },
109
+ slots: {}
104
110
  };
105
111
  model.value.form = mergeObjects(
106
112
  defaultFormAttrs,
@@ -138,7 +144,6 @@ const getItemRulesByItem = (item) => {
138
144
  }
139
145
  // 获取item属性并合并规则
140
146
  const itemInfo = { ...itemDefaultRule, ...item };
141
-
142
147
  //必填验证
143
148
  if (itemInfo.required) {
144
149
  itemRules.push({ required: true, message: `${itemInfo.label}不能为空!`, trigger: 'blur' });
@@ -204,7 +209,9 @@ const getItemRulesByItem = (item) => {
204
209
  return itemRules;
205
210
  }
206
211
 
207
- onMounted(() => { load(); })
212
+ onMounted(() => {
213
+ load();
214
+ })
208
215
 
209
216
  const load = () => {
210
217
  if (!model.value.form.inline) {
@@ -221,11 +228,14 @@ const load = () => {
221
228
  }
222
229
  };
223
230
 
231
+ onBeforeUnmount(() => {
232
+ console.log('destroy');
233
+ })
234
+
224
235
  watch(() => model.value.form.columns, () => load());
225
236
  watch(() => model.value.form.inline, () => load());
226
237
 
227
238
  const columnsWidth = computed(() => convertToPx(model.value.form.style.width) / model.value.form.columns);
228
- console.log(columnsWidth.value);
229
239
  //表单项
230
240
  const items = computed(() => Object.fromEntries(Object.entries(model.value)
231
241
  .filter(a => a[1].type != "hidden")
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <template v-for="(item, key) of getQueryModel(props.more)" :key="key">
3
+ <slot :name="`query-item-${key}`" :item :model>
4
+ <el-form-item :label="item.label" v-bind="{ ...model.queryItems, ...item?.search }">
5
+ <slot :name="'query-' + key" :item :model>
6
+ <g-ctrl v-model="queryModel[key]" :item :ctrlKey="key" :model>
7
+ <template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
8
+ <slot :name="slotKey" :data :item :model></slot>
9
+ </template>
10
+ </g-ctrl>
11
+ </slot>
12
+ <template #label>
13
+ <slot :name="'query-label-' + key" :item :model></slot>
14
+ </template>
15
+ </el-form-item>
16
+ </slot>
17
+ </template>
18
+ </template>
19
+
20
+ <script setup>
21
+ import gCtrl from './g-ctrl.vue';
22
+ import { computed, ref } from "vue";
23
+ const model = defineModel({ required: true });
24
+ const props = defineProps(["more"]);
25
+ const queryModel = defineModel("info", { required: true });
26
+ const getQueryModel = (flag) => computed(() =>
27
+ Object.fromEntries(Object.entries(model.value)
28
+ .filter(a => a[1].search && a[1].search.more === flag).map(key => [key[0], key[1]]))).value;
29
+ </script>
30
+
31
+ <style lang="scss" scoped></style>
@@ -0,0 +1,217 @@
1
+ <template>
2
+ <div class="g-query-container" style="position: relative;">
3
+ <el-form v-bind="filterObject(model.query, k => !['query', 'more', 'reset'].includes(k))">
4
+ <g-query-item v-model="model" v-model:info="queryModel" :more="undefined">
5
+ <template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
6
+ <slot :name="slotKey" :model></slot>
7
+ </template>
8
+ </g-query-item>
9
+ <el-form-item>
10
+ <el-button v-bind="model.query.query" @click="model.query.query.click()">
11
+ {{ model.query.query.label }}
12
+ </el-button>
13
+ <el-button v-bind="model.query.reset" @click="model.query.reset.click()">
14
+ {{ model.query.reset.label }}
15
+ </el-button>
16
+ <el-button v-bind="model.query.more" @click="model.query.more.click()"
17
+ v-if="model.query.more.mode !== 3">
18
+ {{ model.query.more.label }}
19
+ </el-button>
20
+ <el-popover v-bind="model.query.more.dialog" v-if="model.query.more.mode == 3">
21
+ <template #reference>
22
+ <el-button v-bind="model.query.more">
23
+ {{ model.query.more.label }}
24
+ </el-button>
25
+ </template>
26
+ <template #default>
27
+ <el-form v-bind="filterObject(model.query, k => !['query', 'more', 'reset'].includes(k))">
28
+ <g-query-item v-model="model" v-model:info="queryModel" :more="true">
29
+ <template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
30
+ <slot :name="slotKey" :model></slot>
31
+ </template>
32
+ </g-query-item>
33
+ </el-form>
34
+ </template>
35
+ </el-popover>
36
+ <slot name="btns"></slot>
37
+ </el-form-item>
38
+ </el-form>
39
+ <Transition :duration="300" name="nested">
40
+ <div v-if="isShowMore && !model.query.more.hidden && model.query.more.mode == 1" class="outer">
41
+ <div class="inner">
42
+ <el-form v-bind="filterObject(model.query, k => !['query', 'more', 'reset'].includes(k))"
43
+ v-show="isShowMore" v-if="model.query.more.mode == 1">
44
+ <g-query-item v-model="model" v-model:info="queryModel" :more="true">
45
+ <template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
46
+ <slot :name="slotKey" :model></slot>
47
+ </template>
48
+ </g-query-item>
49
+ </el-form>
50
+ </div>
51
+ </div>
52
+ </Transition>
53
+ <el-drawer v-model="isShowMore" title="更多查询" :show-close="false" v-bind="model.query.more.dialog"
54
+ v-if="isShowMore && !model.query.more.hidden && model.query.more.mode == 2">
55
+ <el-form v-bind="filterObject(model.query, k => !['query', 'more', 'reset'].includes(k))">
56
+ <g-query-item v-model="model" v-model:info="queryModel" :more="true">
57
+ <template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
58
+ <slot :name="slotKey" :model></slot>
59
+ </template>
60
+ </g-query-item>
61
+ </el-form>
62
+ <template #footer v-if="!model.query.more.dialog.footer.hidden">
63
+ <div v-bind="model.query.more.dialog.footer">
64
+ <el-button v-bind="model.query.query" @click="model.query.query.click()">
65
+ {{ model.query.query.label }}
66
+ </el-button>
67
+ <el-button v-bind="model.query.reset" @click="model.query.reset.click()">
68
+ {{ model.query.reset.label }}
69
+ </el-button>
70
+ </div>
71
+ </template>
72
+ </el-drawer>
73
+ </div>
74
+ </template>
75
+
76
+ <script setup>
77
+ import { ref, inject } from 'vue'
78
+ import gQueryItem from './g-query-item.vue';
79
+ import { mergeObjects, filterObject } from './index';
80
+ const model = defineModel({ required: true });
81
+ const emits = defineEmits(['query', 'reset']);
82
+ const options = inject('options');
83
+ const isShowMore = ref(false);
84
+ let initValues = Object.fromEntries(Object.entries(model.value).filter(a => a[1].search).map(([key, val]) => [key, val.value]));
85
+ const queryModel = ref(initValues);
86
+ const defaultQueryAttrs = {
87
+ hidden: false,
88
+ type: "hidden",
89
+ labelWidth: 100,
90
+ inline: true,
91
+ style: { display: "flex", flex: 1, "flex-wrap": "wrap" },
92
+ more: {
93
+ mode: 2,
94
+ hidden: false,
95
+ type: "primary",
96
+ label: "更多",
97
+ click: () => {
98
+ isShowMore.value = !isShowMore.value;
99
+ },
100
+ },
101
+ reset: {
102
+ label: "重置",
103
+ type: "primary",
104
+ hidden: false,
105
+ plain: false,
106
+ click: () => {
107
+ queryModel.value = ref(initValues);
108
+ emits('reset', queryModel.value);
109
+ },
110
+ },
111
+ query: {
112
+ hidden: false,
113
+ type: "primary",
114
+ label: "查询",
115
+ click: () => {
116
+ emits('query', queryModel.value);
117
+ isShowMore.value = false;
118
+ }
119
+ }
120
+ }
121
+
122
+ // 查询表单属性
123
+ model.value.query = mergeObjects(defaultQueryAttrs, options?.query, model.value.query);
124
+
125
+ // 表单 查询更多 属性 drawer 方式2 和 popover 方式3
126
+ model.value.query.more.dialog = model.value.query.more.mode == 2 ? mergeObjects({
127
+ title: "更多查询", showClose: false, size: '30%', direction: "ttb", footer: {
128
+ hidden: false,
129
+ style: { textAlign: 'center' }
130
+ }
131
+ }, model.value.query.more.dialog) : model.value.query.more.mode == 3 ? mergeObjects({
132
+ placement: "top-start", title: "更多查询", width: 1200, trigger: "click"
133
+ }, model.value.query.more.dialog) : {};
134
+
135
+
136
+ // 表单查询项属性
137
+ const defaultQueryItemsAttrs = {
138
+ type: "hidden",
139
+ labelPosition: 'right',
140
+ style: {
141
+ width: "250px"
142
+ }
143
+ };
144
+ model.value.queryItems = mergeObjects(defaultQueryItemsAttrs, options?.queryItems, model.value.queryItems);
145
+
146
+ </script>
147
+
148
+ <style scoped>
149
+ .g-query-container {
150
+ display: flex;
151
+ flex: 1;
152
+ flex-direction: column;
153
+ padding: 10px;
154
+ box-sizing: border-box;
155
+ }
156
+
157
+ .outer {
158
+ /* position: absolute; */
159
+ min-height: 100px;
160
+ border-radius: 10px;
161
+ background-color: rgba(255, 255, 255, 0.8);
162
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
163
+ top: 60px;
164
+ padding: 10px;
165
+ width: 100%;
166
+ box-sizing: border-box;
167
+ }
168
+
169
+ .inner {
170
+ border-radius: 0;
171
+ min-height: 100px;
172
+ border: 1px solid #f2f2f2;
173
+ padding: 20px;
174
+ box-sizing: border-box;
175
+ width: 100%;
176
+ background-color: rgba(255, 255, 255, 1);
177
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
178
+ }
179
+
180
+ .nested-enter-active,
181
+ .nested-leave-active {
182
+ transition: all 0.3s ease-in-out;
183
+ }
184
+
185
+ /* delay leave of parent element */
186
+ .nested-leave-active {
187
+ transition-delay: 0.25s;
188
+ }
189
+
190
+ .nested-enter-from,
191
+ .nested-leave-to {
192
+ transform: translateY(-100px);
193
+ opacity: 0;
194
+ }
195
+
196
+ /* we can also transition nested elements using nested selectors */
197
+ .nested-enter-active .inner,
198
+ .nested-leave-active .inner {
199
+ transition: all 0.3s ease-in-out;
200
+ }
201
+
202
+ /* delay enter of nested element */
203
+ .nested-enter-active .inner {
204
+ transition-delay: 0.25s;
205
+ }
206
+
207
+ .nested-enter-from .inner,
208
+ .nested-leave-to .inner {
209
+ transform: translateY(-100px);
210
+ /*
211
+ Hack around a Chrome 96 bug in handling nested opacity transitions.
212
+ This is not needed in other browsers or Chrome 99+ where the bug
213
+ has been fixed.
214
+ */
215
+ opacity: 0.001;
216
+ }
217
+ </style>
@@ -1,8 +1,32 @@
1
1
  <template>
2
- <el-table class="g-table-container" v-bind="{ ...$attrs, ...model.table }">
2
+ <div class="table-query-container">
3
+ <slot name="query">
4
+ <g-query v-model="model" @query="query" @reset="reset">
5
+ <template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
6
+ <slot :name="slotKey" :model></slot>
7
+ </template>
8
+ <template #btns>
9
+ <slot name="btns">
10
+ <div class="btns" v-if="model.control.add.auth()">
11
+ <slot name="control-add-left"></slot>
12
+ <slot name="control-add">
13
+ <el-button v-bind="model.control.add" @click="model.control.add.click(model)">{{
14
+ model.control.add.label
15
+ }}</el-button>
16
+ </slot>
17
+ <slot name="control-add-right"></slot>
18
+ </div>
19
+ </slot>
20
+
21
+ </template>
22
+ </g-query>
23
+ </slot>
24
+
25
+ </div>
26
+ <el-table class="g-table-container" v-bind="{ ...$attrs, ...filterObject(model.table, k => k !== 'page') }">
3
27
  <slot>
4
28
  <el-table-column :prop="key" v-for="(value, key) of tableColumns" :key="key"
5
- v-bind="{ ...itemValue, ...value }" header-align="center">
29
+ v-bind="{ ...model.tableColumns, ...value }" header-align="center">
6
30
  <template #default="{ row, column, $index }"
7
31
  v-if="value.type != 'selection' && value.type != 'index' && value.type != 'expand'">
8
32
  <slot :name="`${key}`" :row :column :$index>
@@ -65,18 +89,20 @@
65
89
  <script setup>
66
90
  import dayjs from 'dayjs';
67
91
  import { ElMessageBox } from 'element-plus';
68
- import { computed, onMounted, ref, watchEffect, h, inject } from 'vue';
92
+ import { computed, watchEffect, inject, ref, h } from 'vue';
69
93
  import GForm from './g-form.vue';
70
- import { openModal, mergeObjects,convertToPx } from './index';
94
+ import gQuery from './g-query.vue';
95
+ import { openModal, mergeObjects, convertToPx, filterObject } from './index';
71
96
 
72
97
  defineOptions({
73
98
  name: "g-table",
74
99
  inheritAttrs: false
75
100
  })
76
101
 
77
- const emits = defineEmits(['load', 'view', "edit", "delete"]);
102
+ const emits = defineEmits(['load', 'view', "edit", "delete", 'add']);
78
103
  const model = defineModel({ required: true });
79
104
  const options = inject('options');
105
+ const queryInfo = ref({});
80
106
 
81
107
  //table default attrs
82
108
  const defaultTableAttrs = {
@@ -86,10 +112,10 @@ const defaultTableAttrs = {
86
112
  emptyText: '暂无数据',
87
113
  fit: false,
88
114
  type: "hidden",
89
- height: "calc(100vh - 55px)",
115
+ height: "calc(100vh - 65px)",
90
116
  load: () => {
91
117
  let { currentPage, pageSize } = model.value.table.page;
92
- emits('load', { currentPage, pageSize }, (data, total) => {
118
+ emits('load', { currentPage, pageSize, ...queryInfo.value }, (data, total) => {
93
119
  model.value.table.data = data;
94
120
  model.value.table.page.total = total;
95
121
  });
@@ -113,78 +139,115 @@ model.value.table = mergeObjects(
113
139
  options?.table,
114
140
  model.value.table
115
141
  );
116
-
117
142
  const defaultControl = {
118
143
  type: 'control', label: '操作', edit: false, width: 250, fixed: 'right',
119
144
  style: { ...model.value?.control?.style },
120
145
  add: {
121
146
  label: '新增', text: false, type: 'primary',
147
+ style: {
148
+ marginLeft: "10px",
149
+ },
122
150
  dialog: {
123
151
  title: '新增',
124
- popMode: "dialog",
125
- slots: {
126
- default: () => h(GForm, { modelValue: model.value }),
127
- },
128
- },
129
- auth: () => {
130
- return true;
152
+ mode: "drawer",
131
153
  },
132
- click: (row, column, $index, m) => {
133
- model.value.form.disabled = undefined;
134
- emits("add", row, column, $index, m);
135
- Object.keys(row).forEach(key => {
154
+ auth: () => true,
155
+ click: (m) => {
156
+ model.value.form = {
157
+ ...model.value.form,
158
+ type: 'hidden',
159
+ disabled: undefined,
160
+ footer: { hidden: false }
161
+ };
162
+ let w = model.value?.form?.style?.width || 600;
163
+ if (model.value.control.add.dialog.mode == "drawer") {
164
+ model.value.control.add.dialog.size = convertToPx(w) + 45;
165
+ } else {
166
+ model.value.control.add.dialog.width = convertToPx(w) + 35;
167
+ }
168
+ emits("add", m);
169
+ Object.keys(initFormData).forEach(key => {
136
170
  if (model.value[key]) {
137
- model.value[key].value = row[key];
171
+ model.value[key].value = initFormData[key];
138
172
  }
139
173
  });
140
- openModal(model.value.control.add.dialog, model.value?.control?.add?.dialog?.popMode);
174
+ let colse = openModal(
175
+ {
176
+ ...model.value?.control?.add?.dialog,
177
+ slots: {
178
+ default: () => h(GForm, {
179
+ modelValue: model.value,
180
+ ...model.value.form,
181
+ key: new Date(),
182
+ onHandSubmit: () => {
183
+ colse();
184
+ },
185
+ }, { ...model.value.form.slots })
186
+ }
187
+ }, model.value?.control?.add?.dialog?.mode);
141
188
  },
142
189
  },
143
190
  view: {
144
191
  label: '查看', text: true, type: 'success',
145
192
  dialog: {
146
193
  title: '查看',
147
- popMode: "dialog",
148
- slots: {
149
- default: () => h(GForm, { modelValue: model.value }),
150
- },
194
+ mode: "dialog",
151
195
  },
152
196
  auth: (row, column, $index) => {
153
197
  return false;
154
198
  },
155
199
  click: (row, column, $index, m) => {
200
+ model.value.form = {
201
+ ...model.value.form,
202
+ type: 'hidden',
203
+ disabled: true,
204
+ footer: { hidden: true }
205
+ };
156
206
  let w = model.value?.form?.style?.width || 600;
157
- if (model.value.control.view.dialog.popMode == "drawer") {
207
+ if (model.value.control.view.dialog.mode == "drawer") {
158
208
  model.value.control.view.dialog.size = convertToPx(w) + 45;
159
209
  } else {
160
210
  model.value.control.view.dialog.width = convertToPx(w) + 35;
161
211
  }
162
- model.value.form.disabled = true;
163
212
  emits("view", row, column, $index, m);
164
213
  Object.keys(row).forEach(key => {
165
214
  if (model.value[key]) {
166
215
  model.value[key].value = row[key];
167
216
  }
168
217
  });
169
- openModal(model.value.control.view.dialog, model.value?.control?.view?.dialog?.popMode);
218
+ let colse = openModal(
219
+ {
220
+ ...model.value?.control?.view?.dialog,
221
+ slots: {
222
+ default: () => h(GForm, {
223
+ modelValue: model.value,
224
+ ...model.value.form,
225
+ onHandSubmit: () => {
226
+ colse();
227
+ },
228
+ }, { ...model.value.form.slots })
229
+ }
230
+ }, model.value?.control?.view?.dialog?.mode);
170
231
  },
171
232
  },
172
233
  edit: {
173
234
  label: '编辑', text: true, type: 'primary',
174
235
  dialog: {
175
236
  title: '编辑',
176
- popMode: "dialog",
177
- slots: {
178
- default: () => h(GForm, { modelValue: model.value }),
179
- },
237
+ mode: "dialog",
180
238
  },
181
239
  auth: (row, column, $index) => {
182
240
  return true;
183
241
  },
184
242
  click: (row, column, $index, m) => {
185
- model.value.form.disabled = undefined;
243
+ model.value.form = {
244
+ ...model.value.form,
245
+ type: 'hidden',
246
+ disabled: undefined,
247
+ footer: { hidden: false }
248
+ };
186
249
  let w = model.value?.form?.style?.width || 600;
187
- if (model.value.control.edit.dialog.popMode == "drawer") {
250
+ if (model.value.control.edit.dialog.mode == "drawer") {
188
251
  model.value.control.edit.dialog.size = convertToPx(w) + 45;
189
252
  } else {
190
253
  model.value.control.edit.dialog.width = convertToPx(w) + 35;
@@ -195,7 +258,19 @@ const defaultControl = {
195
258
  model.value[key].value = row[key];
196
259
  }
197
260
  });
198
- openModal(model.value?.control?.edit?.dialog, model.value?.control?.edit?.dialog?.popMode);
261
+ let colse = openModal(
262
+ {
263
+ ...model.value?.control?.edit?.dialog,
264
+ slots: {
265
+ default: () => h(GForm, {
266
+ modelValue: model.value,
267
+ ...model.value.form,
268
+ onHandSubmit: () => {
269
+ colse();
270
+ },
271
+ }, { ...model.value.form.slots })
272
+ }
273
+ }, model.value?.control?.edit?.dialog?.mode);
199
274
  },
200
275
  },
201
276
  delete: {
@@ -212,6 +287,7 @@ const defaultControl = {
212
287
  emits("delete", { row, column, $index }, (res) => {
213
288
  if (res) {
214
289
  model.value.table.data.splice($index, 1);
290
+ model.value.table.page.total--;
215
291
  }
216
292
  })
217
293
  }).catch(() => { });
@@ -226,12 +302,24 @@ model.value.control = mergeObjects(
226
302
  model.value?.control
227
303
  );
228
304
 
229
- //table column default attrs
230
- const itemValue = ref({
231
- width: 100, align: "center", formatter: (row, column, cellValue, index) => {
305
+ const defaultTableColumnsAttrs = {
306
+ type: "hidden",
307
+ width: 120,
308
+ align: "center",
309
+ formatter: (row, column, cellValue, index) => {
232
310
  return cellValue;
233
311
  }
234
- });
312
+ };
313
+
314
+ model.value.tableColumns = mergeObjects(
315
+ defaultTableColumnsAttrs,
316
+ options?.tableColumns,
317
+ model.value?.tableColumns
318
+ );
319
+
320
+ const initFormData = Object.fromEntries(Object.entries(filterObject(model.value, (k, val) => {
321
+ return (val.type != 'control' && val.edit !== false && val.type != 'hidden');
322
+ })).map(([key, val]) => [key, val.value]));
235
323
 
236
324
  //扩展formatter方法
237
325
  const formatterExtends = (item, str) => {
@@ -272,9 +360,17 @@ const formatterExtends = (item, str) => {
272
360
  return trueValue
273
361
  }
274
362
 
275
- onMounted(() => {
363
+ const reset = (q) => {
364
+ console.log(q);
365
+ queryInfo.value = q.value;
366
+ //model.value.table.load();
367
+ }
368
+
369
+ const query = (q) => {
370
+ queryInfo.value = q;
371
+ //model.value.table.load();
372
+ }
276
373
 
277
- });
278
374
 
279
375
  watchEffect(() => {
280
376
  model.value.table.load();
@@ -290,6 +386,4 @@ const tableColumns = computed(() => Object.fromEntries(
290
386
  return [key[0], key[1]]
291
387
  }).sort((a, b) => a[1].sort - b[1].sort))
292
388
  );
293
- </script>
294
-
295
- <style lang="scss" scoped></style>
389
+ </script>
@@ -1,34 +1,90 @@
1
- import { App } from 'vue';
1
+ // 导入Vue的Component模块
2
2
  import { Component } from 'vue';
3
- import { ElDialogProps, ElDrawerProps } from 'element-plus';
4
-
5
- declare module 'vue' {
6
- interface ComponentCustomProperties {
7
- openModel: typeof openModal;
8
- }
9
- }
3
+ // element-plus库中导入ElDialog和ElDrawer组件
4
+ import { ElDialog, ElDrawer } from 'element-plus';
10
5
 
6
+ /**
7
+ * 全局选项的接口定义
8
+ */
11
9
  export interface GlobalOptions {
12
10
  // 在这里定义全局选项的类型
13
11
  }
14
12
 
13
+ /**
14
+ * 打开模态框的属性接口定义
15
+ */
15
16
  export interface OpenModalProps {
17
+ // 在这里定义传递给模态组件的属性类型
16
18
  slots?: {
17
- default?: () => any;
18
- header?: () => any;
19
- footer?: () => any;
19
+ // 默认插槽的函数类型定义
20
+ default?: (a: any) => any;
21
+ // 头部插槽的函数类型定义
22
+ header?: (p: any) => any;
23
+ // 底部插槽的函数类型定义
24
+ footer?: (p: any) => any;
20
25
  };
21
- // 在这里定义其他传递给openModal函数的属性
22
26
  }
23
27
 
24
- export function install(app: App, options?: GlobalOptions): void;
25
- export function openModal(props?: OpenModalProps, popMode?: 'dialog' | 'drawer'): void;
26
- export function convertToPx(value: string | number, referenceSize?: number): number;
27
- export function mergeObjects<T extends object>(...objects: T[]): T;
28
+ /**
29
+ * 转换为像素的选项接口定义
30
+ */
31
+ export interface ConvertToPxOptions {
32
+ // 参考尺寸的可选属性,类型为number
33
+ referenceSize?: number;
34
+ }
28
35
 
29
- declare const components: {
30
- gTable: Component;
31
- gForm: Component;
32
- };
36
+ /**
37
+ * 合并对象的选项接口定义
38
+ */
39
+ export interface MergeObjectsOptions {
40
+ // 在这里定义合并对象的选项类型
41
+ }
42
+
43
+ /**
44
+ * 过滤对象的选项接口定义
45
+ */
46
+ export interface FilterObjectOptions {
47
+ // 过滤函数的可选属性,类型为(key: string, value: any) => boolean
48
+ filter?: (key: string, value: any) => boolean;
49
+ }
33
50
 
34
- export default components;
51
+ /**
52
+ * 打开模态框的函数定义
53
+ * @param {OpenModalProps} [props] - 传递给模态组件的属性
54
+ * @param {'dialog' | 'drawer'} [mode] - 模态框的模式,可选值为'dialog'或'drawer'
55
+ * @returns {() => void} - 返回一个函数,用于关闭模态框
56
+ */
57
+ export function openModal(props?: OpenModalProps, mode?: 'dialog' | 'drawer'): () => void;
58
+
59
+ /**
60
+ * 将值转换为像素的函数定义
61
+ * @param {string | number} value - 需要转换的值
62
+ * @param {ConvertToPxOptions} [options] - 转换选项
63
+ * @returns {number} - 转换后的像素值
64
+ */
65
+ export function convertToPx(value: string | number, options?: ConvertToPxOptions): number;
66
+
67
+ /**
68
+ * 合并多个对象的函数定义
69
+ * @param {...Record<string, any>} objects - 需要合并的对象
70
+ * @returns {Record<string, any>} - 合并后的对象
71
+ */
72
+ export function mergeObjects(...objects: Array<Record<string, any>>): Record<string, any>;
73
+
74
+ /**
75
+ * 过滤对象的函数定义
76
+ * @param {Record<string, any>} obj - 需要过滤的对象
77
+ * @param {FilterObjectOptions} [options] - 过滤选项
78
+ * @returns {Record<string, any>} - 过滤后的对象
79
+ */
80
+ export function filterObject(obj: Record<string, any>, options?: FilterObjectOptions): Record<string, any>;
81
+
82
+ /**
83
+ * 扩展Vue的ComponentCustomProperties接口,添加openModel属性
84
+ */
85
+ declare module 'vue' {
86
+ interface ComponentCustomProperties {
87
+ // openModel属性的类型定义,指向openModal函数
88
+ openModel: typeof openModal;
89
+ }
90
+ }
@@ -2,11 +2,11 @@
2
2
 
3
3
  import ElementPlus from 'element-plus'
4
4
  import { ElDialog, ElDrawer } from "element-plus";
5
+ import zhCn from 'element-plus/es/locale/lang/zh-cn'
5
6
  import gTable from "./g-table.vue";
6
7
  import gForm from "./g-form.vue";
7
8
  import { createApp, h, provide, readonly, ref } from "vue";
8
9
  const globalOptions = {};
9
-
10
10
  const components = [
11
11
  gTable,
12
12
  gForm
@@ -19,42 +19,73 @@ export default {
19
19
  app.component(component.name, component);
20
20
  }
21
21
  app.provide("options", readonly(options));
22
- app.config.globalProperties.openModel = openModal;
22
+ app.config.globalProperties.openModal = openModal;
23
23
  }
24
24
  }
25
- const openModal = (props = {}, popMode = "dialog") => {
25
+
26
+ /**
27
+ * 打开模态对话框的函数。
28
+ * @param {Object} modalProps - 模态对话框的属性。
29
+ * @param {string} [mode="dialog"] - 模态对话框的模式,支持"dialog"和"drawer"。
30
+ * @returns {Function} - 关闭模态对话框的函数。
31
+ */
32
+ const openModal = (modalProps = {}, mode = "dialog") => {
33
+ // 创建一个新的 div 元素
26
34
  const el = document.createElement('div');
27
- const app = createApp({
35
+ // 定义关闭模态对话框的函数
36
+ let closeModal = () => { };
37
+ // 使用 ref 创建一个响应式的 visible 变量
38
+ const visible = ref(true);
39
+ // 创建一个新的 Vue 应用实例
40
+ let modalApp = createApp({
28
41
  setup() {
29
- const visible = ref(true);
30
- const closeModal = () => {
42
+ // 定义关闭模态对话框的函数
43
+ closeModal = () => {
31
44
  visible.value = false;
32
- app.unmount(); // 关闭对话框时卸载组件
33
- delete el.remove(); // 关闭对话框时删除元素
45
+ modalApp.unmount(); // 关闭对话框时卸载组件
46
+ el.remove(); // 关闭对话框时删除元素
47
+ modalApp = null;
34
48
  };
35
- provide("options", globalOptions);
36
- return () => h(popMode == "dialog" ? ElDialog : popMode == "drawer" ? ElDrawer : null, {
49
+ // 返回渲染函数
50
+ return () => h(mode == "dialog" ? ElDialog : mode == "drawer" ? ElDrawer : null, {
37
51
  modelValue: visible.value,
38
52
  'onUpdate:modelValue': closeModal,
39
53
  draggable: true,
40
54
  "append-to-body": true,
41
- ...props
55
+ 'destroy-on-close': true,
56
+ ...modalProps
42
57
  },
43
58
  {
44
- default: props.slots?.default ? () => h('div', {}, props.slots.default()) : null,
45
- header: props.slots?.header ? () => h('div', {}, props.slots.header()) : null,
46
- footer: props.slots?.footer ? () => h('div', {}, props.slots.footer()) : null
59
+ default: modalProps.slots?.default ? () => modalProps.slots.default() : null,
60
+ header: modalProps.slots?.header ? () => h('div', {}, modalProps.slots.header()) : null,
61
+ footer: modalProps.slots?.footer ? () => h('div', {}, modalProps.slots.footer()) : null
47
62
  }
48
63
  );
49
64
  }
50
65
  });
66
+ // 注册全局组件
51
67
  for (const component of components) {
52
- app.component(component.name, component);
68
+ modalApp.component(component.name, component);
53
69
  }
54
- app.use(ElementPlus).mount(el);
70
+ // 提供全局选项
71
+ modalApp.provide("options", globalOptions);
72
+ // 使用 ElementPlus 插件
73
+ modalApp.use(ElementPlus, { locale: zhCn }).mount(el);
74
+ // 将元素添加到 body 中
55
75
  document.body.appendChild(el);
76
+ // 返回关闭模态对话框的函数
77
+ return closeModal;
56
78
  };
57
79
 
80
+
81
+ /**
82
+ * 将值转换为像素的函数,支持px、vh、vw、%和calc表达式。
83
+ * @param {string|number} value - 需要转换的值。
84
+ * @param {number} [referenceSize=window.innerWidth] - 用于转换%值的参考大小。
85
+ * @returns {number} - 转换后的像素值。
86
+ * @throws {Error} - 如果无法识别单位或提供的参考大小无效。
87
+ */
88
+
58
89
  function convertToPx(value, referenceSize = window.innerWidth) {
59
90
  // 如果已经是px,直接返回
60
91
  if (typeof value === 'number') {
@@ -105,6 +136,11 @@ function convertToPx(value, referenceSize = window.innerWidth) {
105
136
  throw new Error('Unsupported unit in value: ' + value);
106
137
  }
107
138
 
139
+ /**
140
+ * 合并多个对象的函数,递归地合并嵌套对象。
141
+ * @param {...Object} objects - 需要合并的对象。
142
+ * @returns {Object} - 合并后的对象。
143
+ */
108
144
 
109
145
  function mergeObjects(...objects) {
110
146
  const result = ref({});
@@ -123,4 +159,23 @@ function mergeObjects(...objects) {
123
159
  }
124
160
  return result.value;
125
161
  }
126
- export { openModal, convertToPx, mergeObjects };
162
+
163
+ /**
164
+ * 过滤对象的函数,根据给定的过滤条件返回一个新的对象。
165
+ * @param {Object} obj - 需要过滤的对象。
166
+ * @param {Function} filter - 过滤条件函数,接收键和值作为参数,返回布尔值。
167
+ * @returns {Object} - 过滤后的新对象。
168
+ */
169
+ function filterObject(obj, filter = (key, value) => filter(key, value)) {
170
+ const result = {};
171
+ for (const key in obj) {
172
+ if (obj.hasOwnProperty(key)) {
173
+ if (filter(key, obj[key])) {
174
+ result[key] = obj[key];
175
+ }
176
+ }
177
+ }
178
+ return result;
179
+ }
180
+
181
+ export { openModal, convertToPx, mergeObjects, filterObject };