@neatui/vue 3.1.0 → 4.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.
Files changed (52) hide show
  1. package/README.md +1 -10
  2. package/package.json +5 -2
  3. package/rollup.config.js +42 -2
  4. package/src/components/basic/IDraggable@b.vue +1 -1
  5. package/src/components/basic/IFollowView.vue +2 -2
  6. package/src/components/basic/LayerView/Layer.vue +193 -42
  7. package/src/components/display/Calendar.vue +6 -6
  8. package/src/components/display/CalendarReg.vue +6 -6
  9. package/src/components/display/PhotoEditor.vue +2 -2
  10. package/src/components/display/TreeView.vue +4 -3
  11. package/src/components/form/Cascader.vue +3 -3
  12. package/src/components/form/DatePicker.vue +2 -2
  13. package/src/components/form/{DateRangePicker@v3.vue → DateRangePicker.vue} +2 -1
  14. package/src/components/form/{DateRangeView@v3.vue → DateRangeView.vue} +11 -11
  15. package/src/components/form/DateView.vue +461 -82
  16. package/src/components/form/ImgUpload.vue +3 -3
  17. package/src/components/form/{MoreSelect@v3.vue → MoreSelect.vue} +1 -1
  18. package/src/components/form/MoreSelectList.vue +1 -1
  19. package/src/components/form/{MoreSelectPanel@v3.vue → MoreSelectPanel.vue} +1 -1
  20. package/src/components/form/MoreSelectPicker.vue +3 -3
  21. package/src/components/form/MoreSelectTags.vue +1 -1
  22. package/src/components/form/PageMoreSelect.vue +1 -1
  23. package/src/components/form/PageSelect.vue +1 -1
  24. package/src/components/form/SearchMoreSelect.vue +1 -1
  25. package/src/components/form/{SearchSelect@v3.vue → SearchSelect.vue} +1 -1
  26. package/src/components/form/{Select@v3.vue → Select.vue} +1 -1
  27. package/src/components/form/SelectList.vue +1 -1
  28. package/src/components/form/SelectPicker.vue +3 -3
  29. package/src/components/form/SelectTree/{SelectTree@v1.vue → SelectTree.vue} +1 -1
  30. package/src/components/form/Switch.vue +2 -1
  31. package/src/components/form/TimeView.vue +6 -6
  32. package/src/components/form/Upload.vue +22 -11
  33. package/src/components/form/index.ts +8 -8
  34. package/src/components/loader/FormLoader/FormLoader.vue +124 -103
  35. package/src/components/loader/LayerLoader/LayerLoader.vue +6 -7
  36. package/src/components/loader/LimitLoader/{LimitLoader@v3.vue → LimitLoader.vue} +4 -4
  37. package/src/components/loader/LimitLoader/index.ts +1 -1
  38. package/src/components/loader/TableLoader/TableLoader.vue +7 -7
  39. package/src/components/loader/TableLoader/TableRender.vue +0 -1
  40. package/src/components/loader/ViewLoader/{ViewLoader@v1.vue → ViewLoader.vue} +124 -103
  41. package/src/components/loader/ViewLoader/index.ts +1 -1
  42. package/src/components/tools/FormDraftsView.vue +4 -4
  43. package/src/components/tools/FormVerifyView.vue +2 -2
  44. package/src/components/tools/MoreTools.vue +5 -5
  45. package/src/components/tools/Pagination@a.vue +4 -4
  46. package/src/components/tools/Pagination@b.vue +4 -4
  47. package/tsconfig.json +1 -2
  48. package/src/components/form/DateView@v2.vue +0 -386
  49. package/src/components/form/DateView@v3.vue +0 -608
  50. package/src/components/tools/MoreTools@v2.vue +0 -74
  51. /package/src/components/form/{Input@v3.vue → Input.vue} +0 -0
  52. /package/src/components/form/{TextArea.vue → Textarea.vue} +0 -0
@@ -11,15 +11,15 @@
11
11
  </template>
12
12
  <template v-if="(!multiple && files && files.length === 0) || (multiple && (!limit || (limit && files && files.length < limit)))">
13
13
  <slot>
14
- <div ui-flex="row cm" ui-form="@a type:upload tips:hover" :class="`upload bg-fore b-solid bk-case b-xs mb-sl ${uploadClass}`" :style="uploadStyle">
14
+ <div ui-flex="row cm" ui-form="@a type:upload tips:hover" :class="`upload bg-fore b-solid b-case b-xs mb-sl ${uploadClass}`" :style="uploadStyle">
15
15
  <div v-if="tips" ui-form-tips>
16
16
  {{ tips }}
17
17
  </div>
18
18
  <input v-if="!crop" type="file" class="pa input" :multiple="multiple" @change="change" />
19
19
  <div v-else class="input pa" @click="uploadClick"></div>
20
20
  <div class="co-note ac input-icon">
21
- <i class="icon icon-upload fs-mm"></i>
22
- <div class="fs-ss">上传图片</div>
21
+ <i class="icon icon-upload fs-ml"></i>
22
+ <div class="fs-sm">上传图片</div>
23
23
  </div>
24
24
  </div>
25
25
  </slot>
@@ -58,7 +58,7 @@
58
58
 
59
59
  <script setup lang="ts">
60
60
  import { reactive, ref, computed, watch, nextTick } from 'vue';
61
- import { Input } from '.';
61
+ import Input from './Input.vue';
62
62
  import { IFollowView } from '../basic';
63
63
  const ifollow: any = ref(null);
64
64
 
@@ -4,7 +4,7 @@
4
4
  <li
5
5
  v-for="(item, idx) of props.options"
6
6
  :key="idx"
7
- :class="`${mv?.some((i: any) => `${i}` === `${item.value}`) ? 'bg-main-o-ss bk-main-o-ml' : 'bk-case'}`"
7
+ :class="`${mv?.some((i: any) => `${i}` === `${item.value}`) ? 'bg-main-o-ss b-main-o-ml' : 'b-case'}`"
8
8
  class="n-sm r-ss b-solid b-xs"
9
9
  @click.stop="select(item.value)"
10
10
  >
@@ -51,7 +51,7 @@
51
51
 
52
52
  <script setup lang="ts">
53
53
  import { reactive, ref, computed, watch } from 'vue';
54
- import { Input } from '.';
54
+ import Input from './Input.vue';
55
55
  import { IFollowView, IPickerView } from '../basic';
56
56
  const ipicker: any = ref(null);
57
57
 
@@ -6,14 +6,14 @@
6
6
  </Input>
7
7
  <template #options>
8
8
  <div class="full n-xs" ui-flex="col xy">
9
- <div class="flex-fixed n-ms b-solid bk-line bb-xs" ui-flex="row xm">
9
+ <div class="flex-fixed n-ms b-solid b-line bb-xs" ui-flex="row xm">
10
10
  <div><button class="co-note" @click="cancel">取消</button></div>
11
11
  <div><button class="co-main" @click="confirm">确定</button></div>
12
12
  </div>
13
13
  <div class="flex-block">
14
14
  <IScrollView class="full n-ms" :pull="false" :load="false">
15
15
  <ul v-if="props.options?.length" class="my-sm-sub">
16
- <li class="ux-hover n-sm r-ss nowrap b-solid bk-case b-xs" v-for="(item, idx) of props.options" :key="idx" @click.stop="select(item.value)">
16
+ <li class="ux-hover n-sm r-ss nowrap b-solid b-case b-xs" v-for="(item, idx) of props.options" :key="idx" @click.stop="select(item.value)">
17
17
  <label style="pointer-events: none" ui-form="@a type:checkbox :block">
18
18
  <input type="checkbox" :name="field" :checked="mv?.some((i: any) => `${i}` === `${item.value}`)" />
19
19
  <span class="ml-sm">{{ item.label || item }}</span>
@@ -30,7 +30,7 @@
30
30
 
31
31
  <script setup lang="ts">
32
32
  import { reactive, ref, computed, watch } from 'vue';
33
- import { Input } from '.';
33
+ import Input from './Input.vue';
34
34
  import { IPickerView, IScrollView } from '../basic';
35
35
  const ipicker: any = ref(null);
36
36
  const emits = defineEmits(['update:modelValue']);
@@ -5,7 +5,7 @@
5
5
  <li
6
6
  v-for="(item, idx) of props.options"
7
7
  :key="idx"
8
- :class="`${mv?.some((i: any) => `${i}` === `${item.value}`) ? 'bg-main-o-ss bk-main-o-ml' : 'bk-case'}`"
8
+ :class="`${mv?.some((i: any) => `${i}` === `${item.value}`) ? 'bg-main-o-ss b-main-o-ml' : 'b-case'}`"
9
9
  class="nx-ms ny-ss r-sm b-solid b-xs pr"
10
10
  @click.stop="select(item.value)"
11
11
  >
@@ -54,7 +54,7 @@
54
54
 
55
55
  <script setup lang="ts">
56
56
  import { reactive, ref, computed, watch } from 'vue';
57
- import { Input } from '.';
57
+ import Input from './Input.vue';
58
58
  import { IFollowView } from '../basic';
59
59
  const ifollow: any = ref(null);
60
60
 
@@ -42,7 +42,7 @@
42
42
 
43
43
  <script setup lang="ts">
44
44
  import { reactive, ref, computed, watch } from 'vue';
45
- import { Input } from '.';
45
+ import Input from './Input.vue';
46
46
  import { IFollowView } from '../basic';
47
47
 
48
48
  const ifollow: any = ref(null);
@@ -44,7 +44,7 @@
44
44
 
45
45
  <script setup lang="ts">
46
46
  import { reactive, ref, computed } from 'vue';
47
- import { Input } from '.';
47
+ import Input from './Input.vue';
48
48
  import { IFollowView } from '../basic';
49
49
  const ifollow: any = ref(null);
50
50
 
@@ -48,7 +48,7 @@
48
48
 
49
49
  <script setup lang="ts">
50
50
  import { reactive, ref, computed } from 'vue';
51
- import { Input } from '.';
51
+ import Input from './Input.vue';
52
52
  import { IFollowView } from '../basic';
53
53
  const ifollow: any = ref(null);
54
54
  console.warn('「SearchSelect」 即将废弃,建议使用「Select」 设置参数search为true,示例:<Select v-model="value" :search="true" />');
@@ -66,7 +66,7 @@
66
66
 
67
67
  <script setup lang="ts">
68
68
  import { reactive, ref, computed, watch, nextTick } from 'vue';
69
- import { Input } from '.';
69
+ import Input from './Input.vue';
70
70
  import { IFollowView } from '../basic';
71
71
  const ifollow: any = ref(null);
72
72
  const customInputRef: any = ref(null);
@@ -2,7 +2,7 @@
2
2
  <ul v-if="props.options?.length" class="my-sm-sub lh-ss">
3
3
  <li
4
4
  class="hover:bg-main-o-ss n-sl r-ss b-solid b-xs"
5
- :class="`${item.value === mv ? 'bk-main-o-ml bg-main-o-ss' : 'bk-case'}`"
5
+ :class="`${item.value === mv ? 'b-main-o-ml bg-main-o-ss' : 'b-case'}`"
6
6
  v-for="(item, idx) of props.options"
7
7
  :key="idx"
8
8
  @click="mv = item.value === mv ? '' : item.value"
@@ -6,14 +6,14 @@
6
6
  </Input>
7
7
  <template #options>
8
8
  <div class="full n-xs" ui-flex="col xy">
9
- <div class="flex-fixed n-ms b-solid bk-line bb-xs" ui-flex="row xm">
9
+ <div class="flex-fixed n-ms b-solid b-line bb-xs" ui-flex="row xm">
10
10
  <div><button class="co-note" @click="cancel">取消</button></div>
11
11
  <div><button class="co-main" @click="select">确定</button></div>
12
12
  </div>
13
13
  <div class="flex-block">
14
14
  <IScrollView class="full n-ms" :pull="false" :load="false">
15
15
  <ul v-if="props.options?.length" class="my-sm-sub">
16
- <li class="ux-hover n-sm r-ss b-solid bk-case b-xs" v-for="(item, idx) of props.options" :key="idx" @click="mv = item.value">
16
+ <li class="ux-hover n-sm r-ss b-solid b-case b-xs" v-for="(item, idx) of props.options" :key="idx" @click="mv = item.value">
17
17
  <label ui-form="@a type:radio">
18
18
  <input type="radio" :name="item.field" :checked="item.value === mv" /><span>{{ item.label || item }}</span>
19
19
  </label>
@@ -29,7 +29,7 @@
29
29
 
30
30
  <script setup lang="ts">
31
31
  import { reactive, ref, computed } from 'vue';
32
- import { Input } from '.';
32
+ import Input from './Input.vue';
33
33
  import { IPickerView, IScrollView } from '../basic';
34
34
  import { watch } from 'vue';
35
35
  const ipicker: any = ref(null);
@@ -40,7 +40,7 @@
40
40
 
41
41
  <script setup lang="ts">
42
42
  import { reactive, ref, computed, watch } from 'vue';
43
- import { Input } from '..';
43
+ import Input from '../Input.vue';
44
44
  import { IFollowView } from '../../basic';
45
45
  import { TreeView } from '../../display';
46
46
  import { findByJson, filterJson } from '@fekit/utils';
@@ -31,7 +31,8 @@
31
31
  },
32
32
  map: {
33
33
  type: Array as PropType<any[]>,
34
- default: () => [false, true],
34
+ // [checkedValue, uncheckedValue]
35
+ default: () => [true, false],
35
36
  },
36
37
  });
37
38
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <div :class="`${frame ? 'b-solid bk-line b-xs r-sm' : ''}`" ui-flex="col xy">
3
- <div ui-calendar-head="" class="nx-sl ny-sm b-solid bk-line bb-xs">
2
+ <div :class="`${frame ? 'b-solid b-line b-xs r-sm' : ''}`" ui-flex="col xy">
3
+ <div ui-calendar-head="" class="nx-sl ny-sm b-solid b-line bb-xs">
4
4
  <div ui-flex="row lm"></div>
5
5
  <div ui-flex="row cm" class="nx-ss-sub">
6
6
  <p class="mx-ss-sub">
@@ -11,15 +11,15 @@
11
11
  </div>
12
12
  <div ui-flex="row rm"></div>
13
13
  </div>
14
- <div ui-flex="row am" class="fs-xs bold nx-sl nt-sm"><span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span></div>
14
+ <div ui-flex="row am" class="fs-ss bold nx-sl nt-sm"><span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span></div>
15
15
  <div>
16
16
  <ul ui-calendar-days="" ui-flex="row lm" class="flex-wrap nx-sm">
17
17
  <li class="ew7 n-sm ux-none" v-for="(item, idx) in curr.days" :key="idx">
18
18
  <div v-if="item.day" @click="change(item)" ui-cover="-xs">
19
19
  <div
20
20
  ui-flex="col cm"
21
- class="r-sm b-solid bk-none b-xs"
22
- :class="`${item.isToday ? 'bk-main-o-ls' : item.isLastMonth || item.isNextMonth ? 'co-note' : item.isHoliday ? 'co-risk' : ''} ${
21
+ class="r-sm b-solid b-none b-xs"
22
+ :class="`${item.isToday ? 'b-main-o-ls' : item.isLastMonth || item.isNextMonth ? 'co-note' : item.isHoliday ? 'co-risk' : ''} ${
23
23
  state.selected && state.selected === item.date ? 'active bg-main-o-ls co-fore' : 'hover-bg-weak'
24
24
  }`"
25
25
  >
@@ -54,7 +54,7 @@
54
54
  </div>
55
55
  </div>
56
56
  <div ui-flex="row cm" class="nx-ss-sub">
57
- <ul class="fs-xs n-sm-sub" ui-flex="row lm">
57
+ <ul class="fs-ss n-sm-sub" ui-flex="row lm">
58
58
  <li ui-btn="@a s none">年</li>
59
59
  <li ui-btn="@a s none">月</li>
60
60
  <li ui-btn="@a s none">日</li>
@@ -2,9 +2,9 @@
2
2
  <div ui-flex="row lm :wrap" class="neatui-upload mb-sm-sub mr-sm-sub" v-bind="{ ...attrs }">
3
3
  <div v-for="(file, idx) in state.files" :key="idx" ui-flex="col cm" class="flex-fixed pr" :style="`width: ${isNumber(width) ? width + 'em' : width}`" v-bind="itemAttrs">
4
4
  <div class="w-full pr" :style="`box-sizing: content-box; padding-top: ${ratio}%`">
5
- <div class="pa full ot-no ol-no bg-fore n-sm b-solid bk-case b-xs r-sm" ui-flex="col cm">
5
+ <div class="pa full ot-no ol-no bg-fore n-sm b-solid b-case b-xs r-sm" ui-flex="col cm">
6
6
  <!-- 删除按钮 -->
7
- <div class="pa w-xs h-xs ot-ss or-ss bg-fore co-risk lh-xs r-xl parent-hover:show z-ls" ui-flex="row cm" @click="remove(idx)">
7
+ <div v-if="!disabled" class="pa w-sl h-sl ot-ss or-ss bg-fore co-risk lh-xs r-xl parent-hover:show z-ls" ui-flex="row cm" @click="remove(idx)">
8
8
  <svg class="block" style="width: 1.2em; height: 1.2em" viewBox="0 0 1024 1024">
9
9
  <path
10
10
  d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66 0.3L512 563.4l-99.3 118.4-66.1-0.3c-4.4 0-8-3.5-8-8 0-1.9 0.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1 0.3L512 464.6l99.3-118.4 66-0.3c4.4 0 8 3.5 8 8 0 1.9-0.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
@@ -17,7 +17,7 @@
17
17
  <img v-if="file.type === 'image'" class="r-ss" :src="getImageUrl(file)" alt="" />
18
18
  <video v-else-if="file.type === 'video'" class="full r-ss" :src="getImageUrl(file)" controls muted></video>
19
19
  <template v-else-if="file.type === 'pdf'">
20
- <svg t="1705645350800" class="w-ss h-ss" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1913">
20
+ <svg t="1705645350800" class="w-ls h-ls" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1913">
21
21
  <path
22
22
  d="M205.5 64H665l232 232v639c0 13.807-11.193 25-25 25H205.5c-13.807 0-25-11.193-25-25V89c0-13.807 11.193-25 25-25z m449.145 25H205.5v846H872V306.355L654.645 89z"
23
23
  fill="#B7B7BD"
@@ -38,7 +38,7 @@
38
38
  </svg>
39
39
  </template>
40
40
  <template v-else-if="file.type === 'xlsx'">
41
- <svg t="1705645380770" class="w-ss h-ss" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2060">
41
+ <svg t="1705645380770" class="w-ls h-ls" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2060">
42
42
  <path
43
43
  d="M205.799024 64.936585H664.850732l231.773658 231.773659v638.376585c0 13.79353-11.18208 24.97561-24.97561 24.97561H205.799024c-13.79353 0-24.97561-11.18208-24.975609-24.97561V89.912195c0-13.79353 11.18208-24.97561 24.975609-24.97561z m448.70681 24.97561H205.799024v845.174634H871.64878V307.055141L654.505834 89.912195z"
44
44
  fill="#B7B7BD"
@@ -87,7 +87,7 @@
87
87
  </svg>
88
88
  </template>
89
89
  <template v-else-if="file.type === 'docx'">
90
- <svg t="1705645401993" class="w-ss h-ss" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2207">
90
+ <svg t="1705645401993" class="w-ls h-ls" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2207">
91
91
  <path
92
92
  d="M205.5 64H665l232 232v639c0 13.807-11.193 25-25 25H205.5c-13.807 0-25-11.193-25-25V89c0-13.807 11.193-25 25-25z m449.145 25H205.5v846H872V306.355L654.645 89z"
93
93
  fill="#B7B7BD"
@@ -108,7 +108,7 @@
108
108
  </svg>
109
109
  </template>
110
110
  <template v-else-if="file.type === 'pptx'">
111
- <svg t="1705645414803" class="w-ss h-ss" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2354">
111
+ <svg t="1705645414803" class="w-ls h-ls" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2354">
112
112
  <path
113
113
  d="M205.5 64H665l232 232v639c0 13.807-11.193 25-25 25H205.5c-13.807 0-25-11.193-25-25V89c0-13.807 11.193-25 25-25z m449.145 25H205.5v846H872V306.355L654.645 89z"
114
114
  fill="#B7B7BD"
@@ -129,7 +129,7 @@
129
129
  </svg>
130
130
  </template>
131
131
  <template v-else>
132
- <svg t="1705645436666" class="w-ss h-ss" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2501">
132
+ <svg t="1705645436666" class="w-ls h-ls" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2501">
133
133
  <path
134
134
  d="M205.5 64H665l232 232v639c0 13.807-11.193 25-25 25H205.5c-13.807 0-25-11.193-25-25V89c0-13.807 11.193-25 25-25z m449.145 25H205.5v846H872V306.355L654.645 89z"
135
135
  fill="#B7B7BD"
@@ -160,14 +160,20 @@
160
160
 
161
161
  <!-- 上传按钮 -->
162
162
  <template v-if="showUploadButton">
163
- <slot name="btn">
164
- <label class="pr flex-block" ui-form="@a type:upload tips:hover" :style="`width: ${isNumber(width) ? width + 'em' : width}`" v-bind="itemAttrs">
163
+ <slot name="btn" :disabled="disabled">
164
+ <label
165
+ class="pr flex-block"
166
+ :class="{ 'ux-disable': disabled }"
167
+ ui-form="@a type:upload tips:hover"
168
+ :style="`width: ${isNumber(width) ? width + 'em' : width}`"
169
+ v-bind="itemAttrs"
170
+ >
165
171
  <div class="w-full pr" :style="`box-sizing: content-box; padding-top: ${ratio}%`">
166
- <div ui-flex="row cm" :class="`pa ot-no ol-no full upload n-sl bg-fore b-solid bk-case b-xs r-sm ${uploadClass}`" :style="uploadStyle">
172
+ <div ui-flex="row cm" :class="`pa ot-no ol-no full upload n-sl bg-fore b-solid b-case b-xs r-sm ${uploadClass}`" :style="uploadStyle">
167
173
  <div v-if="tips" ui-form-tips>
168
174
  {{ tips }}
169
175
  </div>
170
- <input style="display: none" type="file" class="pa input" :multiple="!max || max > 1" :accept="accept" @change="change" />
176
+ <input style="display: none" type="file" class="pa input" :multiple="!max || max > 1" :accept="accept" :disabled="disabled" @change="change" />
171
177
  <div class="co-note ac input-icon">
172
178
  <svg t="1705642180833" style="width: 1em; height: 1em" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4215">
173
179
  <path
@@ -392,6 +398,7 @@
392
398
 
393
399
  // 删除文件函数
394
400
  const remove = (index: number) => {
401
+ if (props.disabled) return;
395
402
  removeFile(index, false);
396
403
  };
397
404
 
@@ -450,6 +457,10 @@
450
457
  // 文件上传处理
451
458
  const change = (e: Event) => {
452
459
  const target = e.target as HTMLInputElement;
460
+ if (props.disabled) {
461
+ target.value = '';
462
+ return;
463
+ }
453
464
  const selectedFiles = target.files || [];
454
465
 
455
466
  // 检查文件数量限制
@@ -1,4 +1,4 @@
1
- import Input from './Input@v3.vue';
1
+ import Input from './Input.vue';
2
2
  import InputRange from './InputRange.vue';
3
3
  import Switch from './Switch.vue';
4
4
  import Textarea from './Textarea.vue';
@@ -6,24 +6,24 @@ import Textarea from './Textarea.vue';
6
6
  import Checkbox from './Checkbox.vue';
7
7
  import CheckboxItem from './CheckboxItem.vue';
8
8
  import CheckboxGroup from './CheckboxGroup.vue';
9
- import Select from './Select@v3.vue';
9
+ import Select from './Select.vue';
10
10
  import SelectList from './SelectList.vue';
11
11
  import SelectTags from './SelectTags.vue';
12
12
  import SelectPicker from './SelectPicker.vue';
13
- import SearchSelect from './SearchSelect@v3.vue';
14
- import MoreSelect from './MoreSelect@v3.vue';
13
+ import SearchSelect from './SearchSelect.vue';
14
+ import MoreSelect from './MoreSelect.vue';
15
15
  import MoreSelectList from './MoreSelectList.vue';
16
16
  import MoreSelectTags from './MoreSelectTags.vue';
17
17
  import MoreSelectPicker from './MoreSelectPicker.vue';
18
18
  import SearchMoreSelect from './SearchMoreSelect.vue';
19
19
  import PageSelect from './PageSelect.vue';
20
- import SelectTree from './SelectTree/SelectTree@v1.vue';
20
+ import SelectTree from './SelectTree/SelectTree.vue';
21
21
 
22
- import DateView from './DateView@v3.vue';
23
- import DateRangeView from './DateRangeView@v3.vue';
22
+ import DateView from './DateView.vue';
23
+ import DateRangeView from './DateRangeView.vue';
24
24
  import DatePicker from './DatePicker.vue';
25
25
  import TimePicker from './TimePicker.vue';
26
- import DateRangePicker from './DateRangePicker@v3.vue';
26
+ import DateRangePicker from './DateRangePicker.vue';
27
27
  import ImgUpload from './ImgUpload.vue';
28
28
  import Upload from './Upload.vue';
29
29
  import Cascader from './Cascader.vue';
@@ -300,123 +300,146 @@
300
300
  _lw: 6,
301
301
  });
302
302
 
303
- // 监听结构
304
- const unwatchs: any = [];
305
- watch(
306
- [() => props.form, () => props.data, () => props.idx],
307
- ([form = []]) => {
308
- const wkeys: any = {};
309
- const onces: any = [];
310
- state.form = deepcopy(form)?.map((item: any = {}, idx: number) => {
311
- // 计算Label宽度
312
- const _w = clw(item.label) + 2;
313
- if (_w > state._lw) {
314
- state._lw = _w;
315
- }
303
+ // 结构变化时重建字段监听;普通字段变化只触发对应的联动任务
304
+ const unwatchs: Array<() => void> = [];
305
+ let fieldWatcherGeneration = 0;
306
+ const clearFieldWatchers = () => {
307
+ fieldWatcherGeneration += 1;
308
+ unwatchs.splice(0).forEach((unwatch) => {
309
+ unwatch();
310
+ });
311
+ return fieldWatcherGeneration;
312
+ };
313
+ const rebuildFieldWatchers = (form: any = []) => {
314
+ const generation = clearFieldWatchers();
315
+ const watched: any[] = [];
316
+ const onces: any[] = [];
317
+ const taskRuns = new Map<any, number>();
318
+ state.form = deepcopy(form)?.map((item: any = {}, idx: number) => {
319
+ // 计算Label宽度
320
+ const _w = clw(item.label) + 2;
321
+ if (_w > state._lw) {
322
+ state._lw = _w;
323
+ }
316
324
 
317
- if (isObject(item)) {
318
- for (const key in item) {
319
- let val = item[key] || {};
320
- // 处理函数
321
- if (isFunction(val)) {
322
- val = val(deepcopy(props.data), props.form, route, router);
323
- if (isObject(val)) {
324
- if (!isFunction(val.setup)) {
325
- val.setup = item[key];
326
- }
327
- if (!isArray(val.watch)) {
328
- val.watch = deepcopy(form).map(({ field = '' }: any = {}) => field);
329
- }
330
- } else {
331
- val = { value: val, setup: item[key], watch: deepcopy(form).map(({ field = '' }: any = {}) => field) };
332
- }
333
- }
334
- // 对象处理
325
+ if (isObject(item)) {
326
+ for (const key in item) {
327
+ let val = item[key] || {};
328
+ let hasInitialResult = false;
329
+ let initialResult: any;
330
+ // 处理函数
331
+ if (isFunction(val)) {
332
+ const setup = val;
333
+ val = setup(deepcopy(props.data), props.form, route, router);
335
334
  if (isObject(val)) {
336
- const { value = null, setup = () => {}, watch: _watch = [] } = val || {};
337
- // 监听字段为空
338
- if (_watch.length) {
339
- _watch?.forEach((k: any) => {
340
- if (wkeys[k]) {
341
- wkeys[k].push({ idx, key, value, setup });
342
- } else {
343
- wkeys[k] = [{ idx, key, value, setup }];
344
- }
345
- });
346
- } else {
347
- onces.push({ idx, key, value, setup });
335
+ if (!isFunction(val.setup)) {
336
+ val.setup = setup;
337
+ }
338
+ if (!isArray(val.watch)) {
339
+ val.watch = deepcopy(form).map(({ field = '' }: any = {}) => field);
348
340
  }
349
- item[key] = value;
350
341
  } else {
351
- item[key] = val;
342
+ hasInitialResult = true;
343
+ initialResult = val;
344
+ val = { value: val, setup, watch: deepcopy(form).map(({ field = '' }: any = {}) => field) };
352
345
  }
353
346
  }
354
- }
355
-
356
- // 模型处理
357
- if (item.model) {
358
- if (isString(item.model)) {
359
- item.model = [item.model, { verify: false }];
347
+ // 对象处理
348
+ if (isObject(val)) {
349
+ const { value = null, setup = () => {}, watch: _watch = [] } = val || {};
350
+ const task = { idx, key, value, setup, watch: _watch, hasInitialResult, initialResult };
351
+ // 监听字段为空
352
+ if (_watch.length) {
353
+ watched.push(task);
354
+ } else {
355
+ onces.push(task);
356
+ }
357
+ item[key] = value;
358
+ } else {
359
+ item[key] = val;
360
360
  }
361
- } else {
362
- item.model = ['', { verify: false }];
363
361
  }
364
- if (item.model[1] && !Object.prototype.hasOwnProperty.call(item.model[1], 'verify')) {
365
- item.model[1].verify = false;
362
+ }
363
+
364
+ // 模型处理
365
+ if (item.model) {
366
+ if (isString(item.model)) {
367
+ item.model = [item.model, { verify: false }];
366
368
  }
369
+ } else {
370
+ item.model = ['', { verify: false }];
371
+ }
372
+ if (item.model[1] && !Object.prototype.hasOwnProperty.call(item.model[1], 'verify')) {
373
+ item.model[1].verify = false;
374
+ }
367
375
 
368
- // 添加ID
369
- item._fid = `form-${props.idx !== '' ? props.idx + '-' : ''}field-${item.field}`;
376
+ // 添加ID
377
+ item._fid = `form-${props.idx !== '' ? props.idx + '-' : ''}field-${item.field}`;
370
378
 
371
- // 数据路径处理
372
- item._data = props.data;
373
- (item.paths?.split('.') || [])?.forEach((i: any) => {
374
- if (item._data[i]) {
375
- item._data = item._data[i];
376
- }
377
- });
378
- return item;
379
- });
380
- const runsetup = (item: any = {}) => {
381
- const { idx = null, key = null, value = null, setup = null }: any = item || {};
382
- if (state.form[idx] && isFunction(setup)) {
383
- const v = setup(deepcopy(props.data), state.form[idx], route, router);
384
- nextTick(() => {
385
- if (v instanceof Promise) {
386
- state.form[idx][key] = value;
387
- v.then((res: any) => {
388
- state.form[idx][key] = res;
389
- });
390
- } else {
391
- state.form[idx][key] = v;
392
- }
393
- });
379
+ // 数据路径处理
380
+ item._data = props.data;
381
+ (item.paths?.split('.') || [])?.forEach((i: any) => {
382
+ if (item._data[i]) {
383
+ item._data = item._data[i];
394
384
  }
395
- };
396
- // 执行一次
397
- onces?.forEach((item: any = {}) => {
398
- runsetup(item);
399
385
  });
400
- // 监听列表
401
- for (const key in wkeys) {
402
- unwatchs.push(
403
- watch(
404
- () => props.data[key],
405
- () => {
406
- wkeys[key]?.forEach((item: any = {}) => {
407
- runsetup(item);
408
- });
409
- },
410
- {
411
- deep: true,
412
- immediate: true,
413
- },
414
- ),
415
- );
386
+ return item;
387
+ });
388
+ const runsetup = (item: any = {}) => {
389
+ if (generation !== fieldWatcherGeneration) return;
390
+ const { idx = null, key = null, value = null, setup = null }: any = item || {};
391
+ const target = state.form[idx];
392
+ if (target && isFunction(setup)) {
393
+ const runId = (taskRuns.get(item) || 0) + 1;
394
+ taskRuns.set(item, runId);
395
+ const v = item.hasInitialResult ? item.initialResult : setup(deepcopy(props.data), target, route, router);
396
+ item.hasInitialResult = false;
397
+ const isCurrent = () => generation === fieldWatcherGeneration && state.form[idx] === target && taskRuns.get(item) === runId;
398
+ nextTick(() => {
399
+ if (!isCurrent()) return;
400
+ if (v instanceof Promise) {
401
+ target[key] = value;
402
+ v.then((res: any) => {
403
+ if (isCurrent()) {
404
+ target[key] = res;
405
+ }
406
+ });
407
+ } else {
408
+ target[key] = v;
409
+ }
410
+ });
416
411
  }
412
+ };
413
+ // 不声明 watch 的任务只执行一次
414
+ onces.forEach((item: any = {}) => {
415
+ runsetup(item);
416
+ });
417
+ // 每个动态属性只建立一个 watcher,多个依赖在同一轮变化时只执行一次
418
+ watched.forEach((item: any = {}) => {
419
+ unwatchs.push(
420
+ watch(
421
+ () => item.watch.map((key: any) => props.data[key]),
422
+ () => {
423
+ runsetup(item);
424
+ },
425
+ { deep: true, immediate: true },
426
+ ),
427
+ );
428
+ });
429
+ };
430
+ watch(
431
+ () => props.form,
432
+ (form = []) => {
433
+ rebuildFieldWatchers(form);
417
434
  },
418
435
  { deep: true, immediate: true },
419
436
  );
437
+ watch(
438
+ [() => props.data, () => props.idx],
439
+ () => {
440
+ rebuildFieldWatchers(props.form);
441
+ },
442
+ );
420
443
 
421
444
  // 处理
422
445
  watch(
@@ -440,8 +463,6 @@
440
463
  );
441
464
 
442
465
  onBeforeUnmount(() => {
443
- unwatchs?.forEach((unwatch: any) => {
444
- unwatch();
445
- });
466
+ clearFieldWatchers();
446
467
  });
447
468
  </script>