@neatui/nuxt 0.1.0

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 (102) hide show
  1. package/README.md +3 -0
  2. package/package.json +43 -0
  3. package/rollup.config.js +35 -0
  4. package/src/components/basic/IDraggable.vue +84 -0
  5. package/src/components/basic/IDraggable@b.vue +80 -0
  6. package/src/components/basic/IFollowView.vue +211 -0
  7. package/src/components/basic/IPickerView.vue +351 -0
  8. package/src/components/basic/IRouterView.vue +360 -0
  9. package/src/components/basic/IScrollView.vue +127 -0
  10. package/src/components/basic/Icon.vue +54 -0
  11. package/src/components/basic/LayerView/Layer.vue +339 -0
  12. package/src/components/basic/LayerView/index.ts +5 -0
  13. package/src/components/basic/index.ts +7 -0
  14. package/src/components/display/Avatar.vue +1 -0
  15. package/src/components/display/Badge.vue +1 -0
  16. package/src/components/display/Calendar.vue +245 -0
  17. package/src/components/display/CalendarReg.vue +245 -0
  18. package/src/components/display/Card.vue +1 -0
  19. package/src/components/display/Carousel.vue +1 -0
  20. package/src/components/display/ChartView.vue +123 -0
  21. package/src/components/display/Collapse.vue +1 -0
  22. package/src/components/display/Desriptions.vue +1 -0
  23. package/src/components/display/Empty.vue +1 -0
  24. package/src/components/display/Image.vue +112 -0
  25. package/src/components/display/List.vue +1 -0
  26. package/src/components/display/PhotoEditor.vue +181 -0
  27. package/src/components/display/PhotoViewer.vue +50 -0
  28. package/src/components/display/Popover.vue +1 -0
  29. package/src/components/display/QRCode.vue +1 -0
  30. package/src/components/display/Segmented.vue +1 -0
  31. package/src/components/display/Statistic.vue +1 -0
  32. package/src/components/display/Table.vue +1 -0
  33. package/src/components/display/Tabs.vue +1 -0
  34. package/src/components/display/Tag.vue +1 -0
  35. package/src/components/display/Timeline.vue +1 -0
  36. package/src/components/display/Tooltip.vue +1 -0
  37. package/src/components/display/Tour.vue +1 -0
  38. package/src/components/display/Tree.vue +431 -0
  39. package/src/components/display/TreeView.vue +225 -0
  40. package/src/components/display/index.ts +8 -0
  41. package/src/components/form/Cascader.vue +435 -0
  42. package/src/components/form/DatePicker.vue +124 -0
  43. package/src/components/form/DateRangePicker@v2.vue.backup +224 -0
  44. package/src/components/form/DateRangePicker@v3.vue +116 -0
  45. package/src/components/form/DateRangeView@v3.vue +386 -0
  46. package/src/components/form/DateView.vue +229 -0
  47. package/src/components/form/DateView@v2.vue +386 -0
  48. package/src/components/form/DateView@v3.vue +471 -0
  49. package/src/components/form/EditUpload.vue +4 -0
  50. package/src/components/form/ImgUpload.vue +174 -0
  51. package/src/components/form/Input.vue.backup +230 -0
  52. package/src/components/form/Input@v3.vue +267 -0
  53. package/src/components/form/InputNumber.vue +200 -0
  54. package/src/components/form/InputRange.vue +235 -0
  55. package/src/components/form/MoreSelect.vue.backup +144 -0
  56. package/src/components/form/MoreSelect@v3.vue +195 -0
  57. package/src/components/form/MoreSelectList.vue +125 -0
  58. package/src/components/form/MoreSelectPanel@v3.vue +190 -0
  59. package/src/components/form/MoreSelectPicker.vue +124 -0
  60. package/src/components/form/MoreSelectTags.vue +124 -0
  61. package/src/components/form/PageMoreSelect.vue +187 -0
  62. package/src/components/form/PageSelect.vue +189 -0
  63. package/src/components/form/SearchMoreSelect.vue +173 -0
  64. package/src/components/form/SearchSelect.vue.backup +194 -0
  65. package/src/components/form/SearchSelect@v3.vue +202 -0
  66. package/src/components/form/Select@v3.vue +201 -0
  67. package/src/components/form/SelectList.vue +58 -0
  68. package/src/components/form/SelectPicker.vue +97 -0
  69. package/src/components/form/SelectTags.vue +52 -0
  70. package/src/components/form/SelectTree/SelectTree@v1.vue +227 -0
  71. package/src/components/form/Switch.vue +135 -0
  72. package/src/components/form/TextArea.vue +193 -0
  73. package/src/components/form/TimePicker.vue +11 -0
  74. package/src/components/form/TimeView.vue +244 -0
  75. package/src/components/form/Upload.vue +346 -0
  76. package/src/components/form/index.ts +82 -0
  77. package/src/components/loader/FormLoader/FormLoader@v2.vue +422 -0
  78. package/src/components/loader/FormLoader/FormLoader@v3.vue.backup +318 -0
  79. package/src/components/loader/FormLoader/index.ts +2 -0
  80. package/src/components/loader/FormLoader@v1/FormLoader.vue +506 -0
  81. package/src/components/loader/FormLoader@v1/FormRender.vue +277 -0
  82. package/src/components/loader/LimitLoader/LimitLoader.vue.backup +131 -0
  83. package/src/components/loader/LimitLoader/LimitLoader@v2.vue.backup +174 -0
  84. package/src/components/loader/LimitLoader/LimitLoader@v3.vue +183 -0
  85. package/src/components/loader/LimitLoader/index.ts +2 -0
  86. package/src/components/loader/TableLoader/TableColView.vue +115 -0
  87. package/src/components/loader/TableLoader/TableLoader.vue +360 -0
  88. package/src/components/loader/TableLoader/index.ts +2 -0
  89. package/src/components/loader/ViewLoader/ViewLoader@v1.vue +256 -0
  90. package/src/components/loader/ViewLoader/index.ts +2 -0
  91. package/src/components/loader/index.ts +5 -0
  92. package/src/components/tools/FormDraftsView.vue +330 -0
  93. package/src/components/tools/FormVerifyView.vue +206 -0
  94. package/src/components/tools/MoreTools.vue +74 -0
  95. package/src/components/tools/MoreTools@v2.vue +74 -0
  96. package/src/components/tools/Pagination@a.vue +222 -0
  97. package/src/components/tools/Pagination@b.vue +221 -0
  98. package/src/components/tools/index.ts +5 -0
  99. package/src/index.ts +9 -0
  100. package/src/shims-vue.d.ts +5 -0
  101. package/src/store/myui.ts +50 -0
  102. package/tsconfig.json +24 -0
@@ -0,0 +1,183 @@
1
+ <template>
2
+ <div class="full-x" ui-flex="row xt">
3
+ <div class="mr-mm-sub my-sm-sub" ui-flex="row lm :wrap">
4
+ <template v-for="(item, idx) in state.limit" :key="idx">
5
+ <div v-if="!item._close" ui-flex="row lm" v-bind="{ ...(item.attrs || {}) }">
6
+ <span class="nr-sm flex-fixed o-ls">{{ item.label }}{{ item.label ? ':' : '' }}</span>
7
+ <Input v-if="item.model[0] === 'Input'" v-model="state.param[item.field]" :block="false" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
8
+ <Select v-else-if="item.model[0] === 'Select'" v-model="state.param[item.field]" :options="item.enums" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
9
+ <SelectTree v-else-if="item.model[0] === 'SelectTree'" v-model="state.param[item.field]" :options="item.enums" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
10
+ <Cascader v-else-if="item.model[0] === 'Cascader'" v-model="state.param[item.field]" :options="item.enums" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
11
+ <MoreSelect v-else-if="item.model[0] === 'MoreSelect'" v-model="state.param[item.field]" :options="item.enums" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
12
+ <SearchMoreSelect v-else-if="item.model[0] === 'SearchMoreSelect'" v-model="state.param[item.field]" :options="item.enums" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
13
+ <DatePicker
14
+ v-else-if="item.model[0] === 'DatePicker'"
15
+ v-model="state.param[item.field]"
16
+ sz="s"
17
+ v-bind="{ ...(item.model[1] || {}) }"
18
+ @change="(val: any) => (state.param[item.field] = val)"
19
+ />
20
+ <DateRangePicker v-else-if="item.model[0] === 'DateRangePicker'" v-model="state.param[item.field]" sz="s" v-bind="{ ...(item.model[1] || {}) }" />
21
+ <slot v-else :name="item.field" :form="item" :data="param"></slot>
22
+ </div>
23
+ </template>
24
+ </div>
25
+ <div class="mr-sl-sub my-sm-sub nowrap" ui-hide="<pad">
26
+ <IFollowView tipBoxClass="nr-no">
27
+ <button ui-btn="@a s case :border"><i class="icon icon-add2 fs-xs"></i>添加条件</button>
28
+ <template v-if="state.limit.length" #tips>
29
+ <div class="w-mm h-ls nr-sl" ui-scroll="x:hidden :y">
30
+ <div v-for="(item, idx) in state.limit" :key="idx" class="item ux-hover nowrap r-ss">
31
+ <label class="ny-xs nx-sm" ui-form="@a type:checkbox">
32
+ <input :checked="!item._close" type="checkbox" @change="item._close = item._close ? 0 : 1" />
33
+ <span>{{ item.label }}</span>
34
+ </label>
35
+ </div>
36
+ </div>
37
+ </template>
38
+ </IFollowView>
39
+ <button ui-btn="@a s main" @click="fResetLimit">{{ words['common.reset'] || '重置' }}</button>
40
+ </div>
41
+ </div>
42
+ <div class="mr-sl-sub my-sm-sub nowrap" ui-hide=">mob">
43
+ <IFollowView tipBoxClass="nr-no">
44
+ <button ui-btn="@a s case :border"><i class="icon icon-add2 fs-xs"></i>添加条件</button>
45
+ <template v-if="state.limit.length" #tips>
46
+ <div class="w-mm h-ls nr-sl" ui-scroll="x:hidden :y">
47
+ <div v-for="(item, idx) in state.limit" :key="idx" class="item ux-hover nowrap r-ss">
48
+ <label class="ny-xs nx-sm" ui-form="@a type:checkbox">
49
+ <input :checked="!item._close" type="checkbox" @change="item._close = item._close ? 0 : 1" />
50
+ <span>{{ item.label }}</span>
51
+ </label>
52
+ </div>
53
+ </div>
54
+ </template>
55
+ </IFollowView>
56
+ <button ui-btn="@a s main" @click="fResetLimit">{{ words['common.reset'] || '重置' }}</button>
57
+ </div>
58
+ </template>
59
+ <script lang="ts" setup>
60
+ import { computed, reactive, watch } from 'vue';
61
+ import { useRoute } from 'vue-router';
62
+ import { deepcopy, isObject, isString } from '@fekit/utils';
63
+ import { IFollowView } from '../../basic';
64
+ import { Input, Select, SelectTree, MoreSelect, SearchMoreSelect, DatePicker, DateRangePicker, Cascader } from '../../form';
65
+
66
+ const route = useRoute();
67
+
68
+ /**
69
+ * 入参说明
70
+ *
71
+ * words 语言包
72
+ * limit 结构配置
73
+ * param 数据
74
+ */
75
+
76
+ interface LimitProps {
77
+ label?: string | (() => string);
78
+ field: string | (() => string);
79
+ model?: string | Array<any> | (() => string | Array<any>);
80
+ enums?: Array<any> | (() => string | Array<any>);
81
+ rules?: Array<any> | (() => string | Array<any>);
82
+ event?: Array<any> | (() => string | Array<any>);
83
+ attrs?: Array<any> | (() => string | Array<any>);
84
+ value?: any | (() => any);
85
+ clear?: boolean | (() => boolean);
86
+ close?: boolean;
87
+ }
88
+
89
+ // 类型
90
+ interface Props {
91
+ words?: { [key: string | number]: any };
92
+ limit: Array<LimitProps>;
93
+ param: any;
94
+ }
95
+
96
+ const props: any = withDefaults(defineProps<Props>(), {
97
+ words: () => ({}),
98
+ limit: () => [],
99
+ param: () => ({})
100
+ });
101
+
102
+ // 内部数据
103
+ const state: any = reactive({
104
+ name: computed(() => 'confs' + route.path?.replace(/\//g, '_')),
105
+ limit: [],
106
+ param: {}
107
+ });
108
+ // 监听外部配置
109
+ watch(
110
+ () => props.limit,
111
+ () => {
112
+ const _cache = JSON.parse(localStorage.getItem(`${state.name}_limit`) || '{}');
113
+ state.limit = deepcopy(props.limit)?.map((item: any) => {
114
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_close')) {
115
+ item._close = Number(_cache[item.field]?._close);
116
+ } else {
117
+ if (item.close === true || item.close === 1) {
118
+ item._close = 1;
119
+ }
120
+ }
121
+
122
+ // 模型处理
123
+ if (item.model) {
124
+ if (isString(item.model)) {
125
+ item.model = [item.model, { verify: false }];
126
+ }
127
+ } else {
128
+ item.model = ['', { verify: false }];
129
+ }
130
+
131
+ if (!item.model[1] || !isObject(item.model[1])) {
132
+ item.model.push({ verify: false });
133
+ }
134
+
135
+ // 属性处理
136
+ if (item.model[1].class) {
137
+ if (!/\bw-[sml]+/.test(item.model[1].class || '')) {
138
+ item.model[1].class += ' w-ms+';
139
+ }
140
+ } else {
141
+ item.model[1].class = 'w-ms+';
142
+ }
143
+
144
+ return item;
145
+ });
146
+ },
147
+ { deep: true, immediate: true }
148
+ );
149
+ // 缓存交互配置
150
+ watch(
151
+ [() => state.limit],
152
+ () => {
153
+ const _limit: any = {};
154
+ state.limit.forEach((item: any, idx: number) => {
155
+ if (Object.prototype.hasOwnProperty.call(item, '_close')) {
156
+ _limit[item.field] = { _close: item._close ? 1 : 0 };
157
+ if (item._close) {
158
+ delete state.param[item.field];
159
+ }
160
+ }
161
+ });
162
+ localStorage.setItem(`${state.name}_limit`, JSON.stringify(_limit));
163
+ },
164
+ { deep: true }
165
+ );
166
+
167
+ watch(
168
+ () => props.param,
169
+ () => {
170
+ state.param = props.param;
171
+ },
172
+ { deep: true, immediate: true }
173
+ );
174
+
175
+ // 重置筛选
176
+ const fResetLimit = () => {
177
+ for (const key in state.param) {
178
+ if (key !== 'page' && key !== 'pageSize') {
179
+ delete state.param[key];
180
+ }
181
+ }
182
+ };
183
+ </script>
@@ -0,0 +1,2 @@
1
+ import FormLoader from './LimitLoader@v3.vue';
2
+ export default FormLoader;
@@ -0,0 +1,115 @@
1
+ <template>
2
+ <template v-if="isArray(json.child)">
3
+ <div :class="json?.attrs?.class?.includes('wrap') ? 'wrap' : 'nowrap'" v-bind="json.attrs" v-on="event(json, data)">
4
+ <TableColView v-for="(sub, idx) in col.child" :key="idx" :col="sub" :data="data" />
5
+ </div>
6
+ </template>
7
+ <template v-else-if="json.popup">
8
+ <IFollowView>
9
+ <TableColView :col="{ ...col, popup: null }" :data="data" />
10
+ <template #tips>
11
+ <TableColView :col="isFunction(col.popup) ? col.popup(data) : col.popup" :data="data" />
12
+ </template>
13
+ </IFollowView>
14
+ </template>
15
+ <template v-else>
16
+ <div v-if="json.model === 'Image'" :class="json?.attrs?.class?.includes('wrap') ? 'wrap' : 'nowrap'" ui-img="@a read :round" v-bind="json.attrs" v-on="event(json, data)">
17
+ <img :src="json.value || data[json.field] || DefaultImage" alt="" />
18
+ </div>
19
+ <div
20
+ v-else
21
+ :class="json?.attrs?.class?.includes('wrap') ? 'wrap' : 'nowrap'"
22
+ v-bind="json.attrs"
23
+ v-on="event(json, data)"
24
+ v-html="
25
+ json.value !== null && json.value !== undefined
26
+ ? isFunction(json.value)
27
+ ? json.value(json)
28
+ : json.value
29
+ : findEnumName(json.enums, data[json.field]) !== null && findEnumName(json.enums, data[json.field]) !== undefined
30
+ ? findEnumName(json.enums, data[json.field])
31
+ : '‐‐'
32
+ "
33
+ ></div>
34
+ </template>
35
+ </template>
36
+ <script lang="ts" setup>
37
+ import { computed } from 'vue';
38
+ import { isFunction, isArray, isObject, deepcopy } from '@fekit/utils';
39
+ import { useRoute, useRouter } from 'vue-router';
40
+ import TableColView from './TableColView.vue';
41
+ import { IFollowView } from '../../basic';
42
+
43
+ const DefaultImage =
44
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKYAAACmBAMAAACipulEAAAAHlBMVEXMzMz////z8/Pf39/Z2dnS0tLq6urk5OTu7u74+PjCLuPVAAABxUlEQVRo3u2YsUsDMRSHX9Wzupn22qObVxAd7SCuV1BwvGrVtQcqjlYQHFVEVzv575qklReE9urlFTL8vqUvQz+Se3m5yyMAAAAAAAAAAAAAsFIu7rvz+DiqprxSi7itotxQi8kqOHslzqbHNAUnul3q/PJYutzi01Jn47/KSBm+jxep8yopSojqgklaV5qRDor5zsMKTru4gazTJmEtfKcyQU3Waf/UE3bGXPb7p5fDRwmnuhkWyvJEhmt/JzOiKZtyzph+6Us5O1zY0UTI2TKy5+4nl5W/M9PpT00NmEDG2dbDgiMR5w7R1ix84brycz7oyfGU6yLO3HmIGUUSzoY9m3jxqYAzsRuIt9VYwBm7Z1OTB57Owt1XfQFn649zEOg8YzctiYyz6Wpizxzxcmtunb5K1JGtR65TkdrMiCazsMOHnZ9zlx9ozHXq5XTfyBnr/ZwdPTy30Z6OJr5OfhOf6d934tPZ15mQJjrJSVN4O3mi/NEg5GzkNCVKBZy8estYeTuZdmbuDYWScDIHd29KSTmZEJ26GsUvxpEqJw/gDrvMXTuInsASvYsgeizlvaBAelZlvTUAAAAAAAAAAAAAsEp+AEDOpCBEwOONAAAAAElFTkSuQmCC';
45
+
46
+ // 通过枚举值查找枚举名
47
+ const findEnumName = (enums: any, val: any, join: boolean | string = ' Ι ') => {
48
+ // 转换核心
49
+ const _core = (v: any) => {
50
+ const { label = v }: any = enums.find(({ value = '' }: any) => value == v) || {};
51
+ return label;
52
+ };
53
+ // 判断枚举字典是否可用
54
+ if (enums && enums.find) {
55
+ // 兼容多种入参类型
56
+ if (isArray(val)) {
57
+ // 数组
58
+ const arr = val.map((i: any) => _core(i));
59
+ return join ? arr.join(join) : arr;
60
+ } else {
61
+ return _core(val);
62
+ }
63
+ } else {
64
+ return val;
65
+ }
66
+ };
67
+
68
+ const route = useRoute();
69
+ const router = useRouter();
70
+
71
+ const props: any = defineProps({
72
+ col: {
73
+ type: Object,
74
+ default: () => ({})
75
+ },
76
+ data: {
77
+ type: [Object],
78
+ default: () => ({})
79
+ }
80
+ });
81
+
82
+ // 运行函数计算
83
+ const runfun = (obj: any): any => {
84
+ if (isArray(obj)) {
85
+ obj = obj.map((i: any) => runfun(i));
86
+ } else if (isObject(obj)) {
87
+ for (const k in obj) {
88
+ if (k !== 'event') {
89
+ obj[k] = runfun(obj[k]);
90
+ }
91
+ }
92
+ } else if (isFunction(obj)) {
93
+ obj = obj(deepcopy(props.data));
94
+ }
95
+ return obj;
96
+ };
97
+
98
+ const json = computed(() => runfun(deepcopy(props.col)));
99
+
100
+ // 事件处理
101
+ const event: any = (col: any, data: any): object => {
102
+ const _event: any = {};
103
+ if (isObject(col.event)) {
104
+ for (const key in col.event) {
105
+ const fun = col.event[key];
106
+ if (isFunction(fun)) {
107
+ _event[key] = (...args: any) => {
108
+ return fun({ data, route, router }, ...args);
109
+ };
110
+ }
111
+ }
112
+ }
113
+ return { ..._event };
114
+ };
115
+ </script>
@@ -0,0 +1,360 @@
1
+ <template>
2
+ <div class="full" ui-scroll=":x :y">
3
+ <!-- 桌面端 -->
4
+ <table ui-hide="<pad" ui-table="@b sz:l" ref="tableRef">
5
+ <thead class="table-head-fixed">
6
+ <tr>
7
+ <th v-if="showSelectAll" col-fixed="1" min-width>
8
+ <label class="mb-ss" ui-form="@a type:checkbox"><input type="checkbox" :checked="state.isAllSelect" @change="fSelectAll" /><span></span></label>
9
+ </th>
10
+ <template v-for="(col, idx) in state.table" :key="idx">
11
+ <th v-if="!col._close" class="fs-xs nowrap" :min-width="col.fixed" :col-fixed="col.fixed" :col-fixed-side="col.fixed || 'l'" :data-field="col.field">
12
+ <div :ui-flex="`row ${!slots.operate && idx === state._last ? 'rm' : 'lm'}`">
13
+ <span class="nl-xs" v-if="col.sort" :ui-sort="0" @click="emits('onsort', col)">{{ col.label }}</span>
14
+ <span class="nl-xs" v-else>{{ col.label }}</span>
15
+ <IFollowView v-if="!slots.operate && idx === state._last" tipBoxClass="n-no">
16
+ <button :ui-btn="`@a none s :square`">
17
+ <Icon name="tableloader-setting" class="co-read"></Icon>
18
+ </button>
19
+ <template #tips>
20
+ <div class="w-mm h-ls n-sl" ui-scroll="x:hidden :y">
21
+ <draggable
22
+ v-model="state.table"
23
+ :force-fallback="false"
24
+ item-key="name"
25
+ chosen-class="chosen"
26
+ animation="200"
27
+ filter=".forbid"
28
+ :move="(e: any) => !e.relatedContext.element.fixed"
29
+ >
30
+ <template #item="{ element, index }">
31
+ <div :class="`item ux-hover nowrap r-ss ${element.fixed ? 'forbid' : 'element'}`" :key="index">
32
+ <label ui-form="@a type:checkbox" class="ny-xs nx-sl">
33
+ <input type="checkbox" :checked="!element._close" @change="element._close = element._close ? 0 : 1" />
34
+ <span>
35
+ {{ element.label }}
36
+ <i v-if="element.fixed" class="icon icon-fixed fs-xs"></i>
37
+ </span>
38
+ </label>
39
+ </div>
40
+ </template>
41
+ </draggable>
42
+ </div>
43
+ </template>
44
+ </IFollowView>
45
+ </div>
46
+ </th>
47
+ </template>
48
+ <th v-if="slots.operate" col-fixed="r" class="fs-xs nowrap ar">
49
+ <div ui-flex="row rm">
50
+ <span class="mr-sm">{{ words['operate'] || '操作' }}</span>
51
+ <IFollowView tipBoxClass="n-no">
52
+ <button :ui-btn="`@a none s :square`">
53
+ <Icon name="tableloader-setting" class="co-read"></Icon>
54
+ </button>
55
+ <template #tips>
56
+ <div class="w-mm h-ls n-sl" ui-scroll="x:hidden :y">
57
+ <draggable
58
+ v-model="state.table"
59
+ :force-fallback="false"
60
+ item-key="name"
61
+ chosen-class="chosen"
62
+ animation="200"
63
+ filter=".forbid"
64
+ :move="(e: any) => !e.relatedContext.element.fixed"
65
+ >
66
+ <template #item="{ element, index }">
67
+ <div :class="`item ux-hover nowrap r-ss ${element.fixed ? 'forbid' : 'element'}`" :key="index">
68
+ <label ui-form="@a type:checkbox" class="ny-xs nx-sl">
69
+ <input type="checkbox" :checked="!element._close" @change="element._close = element._close ? 0 : 1" />
70
+ <span>
71
+ {{ element.label }}
72
+ <i v-if="element.fixed" class="icon icon-fixed fs-xs"></i>
73
+ </span>
74
+ </label>
75
+ </div>
76
+ </template>
77
+ </draggable>
78
+ </div>
79
+ </template>
80
+ </IFollowView>
81
+ </div>
82
+ </th>
83
+ </tr>
84
+ </thead>
85
+ <tbody :ui-tbody-load="state.load">
86
+ <template v-if="lists.length">
87
+ <tr v-for="(item, idx) in lists" :key="idx" v-bind="rows.attrs" v-on="event(rows.event, item, 'td')">
88
+ <td v-if="showSelectAll" col-fixed="1" min-width>
89
+ <label class="mb-ss" ui-form="@a type:checkbox"><input type="checkbox" v-model="item.__selected" /><span></span></label>
90
+ </td>
91
+ <template v-for="(col, idx) in state.table" :key="idx">
92
+ <td
93
+ v-if="!col._close"
94
+ :class="`${!slots.operate && idx === state._last ? 'ar' : ''}`"
95
+ :min-width="col.fixed"
96
+ :col-fixed="col.fixed"
97
+ :col-fixed-side="col.fixed || 'l'"
98
+ :data-field="col.field"
99
+ >
100
+ <slot v-if="slots[col.field]" :name="col.field"></slot>
101
+ <TableColView v-else :col="col" :data="item" />
102
+ </td>
103
+ </template>
104
+ <td v-if="slots.operate" col-fixed="r" class="ar"><slot name="operate" :item="item" :idx="idx"></slot></td>
105
+ </tr>
106
+ </template>
107
+ </tbody>
108
+ </table>
109
+ <!-- 移动端 -->
110
+ <div ui-hide=">mob">
111
+ <table class="n-sl" ui-table="@a">
112
+ <thead class="table-head-fixed">
113
+ <tr>
114
+ <th class="fs-xs ar ps nr-no">
115
+ <div ui-flex="row xm">
116
+ <span class="fs-xs bold">信息</span>
117
+ <IFollowView>
118
+ <button :ui-btn="`@a none s :square`"><Icon name="tableloader-setting" class="co-read"></Icon></button>
119
+ <template #tips>
120
+ <draggable :list="state.table" :force-fallback="false" item-key="name" chosen-class="chosen" animation="200">
121
+ <template #item="{ element, index }">
122
+ <div class="item ux-hover nowrap r-ss" :key="index">
123
+ <label ui-form="@a type:checkbox" class="ny-xs nx-sl">
124
+ <input type="checkbox" :checked="!element._close" @change="element._close = element._close ? 0 : 1" />
125
+ <span>{{ element.label }}</span>
126
+ </label>
127
+ </div>
128
+ </template>
129
+ </draggable>
130
+ </template>
131
+ </IFollowView>
132
+ </div>
133
+ </th>
134
+ </tr>
135
+ </thead>
136
+ <tbody :ui-tbody-load="state.load">
137
+ <template v-if="lists.length">
138
+ <tr v-for="(item, idx) in lists" :key="idx" v-bind="rows.attrs" v-on="event(rows.event, item)">
139
+ <td ui-card="@a bk:line" class="mb-sl">
140
+ <div ui-card-body="" class="n-ss">
141
+ <ul>
142
+ <template v-for="(col, idx) in state.table" :key="idx">
143
+ <li v-if="!col._close" :class="`${col.fixed ? 'ps z-sm' : ''}`" ui-flex="row lm">
144
+ <div class="w-sl">{{ col.label }}:</div>
145
+ <TableColView :col="col" :data="item" />
146
+ </li>
147
+ </template>
148
+ <li v-if="slots.operate"><slot name="operate" :item="item" :idx="idx"></slot></li>
149
+ </ul>
150
+ </div>
151
+ </td>
152
+ </tr>
153
+ </template>
154
+ </tbody>
155
+ </table>
156
+ </div>
157
+ <div v-if="!lists.length" class="ny-ls o-mm" ui-flex="col cm">
158
+ <div class="ac">
159
+ <p><i class="icon icon-nodata fs-lm lh-ss"></i></p>
160
+ <p>{{ words['common.nodata'] || '暂无记录' }}</p>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </template>
165
+ <script setup lang="ts">
166
+ import { computed, onMounted, reactive, watch, ref, nextTick, onUnmounted, useSlots } from 'vue';
167
+ import { useRoute, useRouter } from 'vue-router';
168
+ import draggable from 'vuedraggable';
169
+ import { IFollowView, Icon } from '../../basic';
170
+ import { itable } from '@fekit/itable';
171
+ import TableColView from './TableColView.vue';
172
+ import { isFunction, isObject, deepcopy } from '@fekit/utils';
173
+ const route = useRoute();
174
+ const router = useRouter();
175
+ // 外部插槽
176
+ const slots: any = useSlots();
177
+ // 外部方法
178
+ const emits = defineEmits(['update:table', 'onsort', 'refresh']);
179
+
180
+ // 类型定义
181
+ interface JSONRules {
182
+ label: string | (() => string);
183
+ field: string | (() => string);
184
+ paths: string | (() => string);
185
+ model?: string | Array<any> | (() => string | Array<any>);
186
+ enums?: Array<any> | (() => string | Array<any>);
187
+ rules?: Array<any> | (() => string | Array<any>);
188
+ event?: Array<any> | (() => string | Array<any>);
189
+ attrs?: Array<any> | (() => string | Array<any>);
190
+ value?: any | (() => any);
191
+ clear?: boolean | (() => boolean);
192
+ sort?: boolean | (() => boolean);
193
+ }
194
+ interface Props {
195
+ words?: { [key: string]: any };
196
+ table: Array<JSONRules>;
197
+ lists: Array<any>;
198
+ showSelectAll?: boolean;
199
+ rows?: {
200
+ attrs?: { [key: string]: any };
201
+ event?: { [key: string]: any };
202
+ };
203
+ }
204
+ // 外部入参
205
+ const props: any = withDefaults(defineProps<Props>(), {
206
+ words: () => ({}),
207
+ table: () => [],
208
+ lists: () => [],
209
+ showSelectAll: true,
210
+ rows: () => ({ attrs: {}, event: {} })
211
+ });
212
+
213
+ // 内部数据
214
+ const state: any = reactive({
215
+ name: computed(() => 'confs' + route.path?.replace(/\//g, '_')),
216
+ load: 0,
217
+ tool: 1,
218
+ mode: 0,
219
+ id: 0,
220
+ limit: computed(() => {
221
+ const _cache = JSON.parse(localStorage.getItem(`${state.name}_limit`) || '{}');
222
+ return (props.limit || [])?.map((item: any) => {
223
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_close')) {
224
+ item._close = _cache[item.field]?._close;
225
+ } else {
226
+ if (item.close === true || item.close === 1 || item.close === 'always') {
227
+ item._close = 1;
228
+ }
229
+ }
230
+ return item;
231
+ });
232
+ }),
233
+ table: [],
234
+ param: {},
235
+ // 列表是否全选
236
+ isAllSelect: computed(() => {
237
+ return (
238
+ props.lists.length &&
239
+ props.lists.every((item: any) => {
240
+ return item.__selected;
241
+ })
242
+ );
243
+ }),
244
+ // 列表是否有在选行
245
+ isHasSelect: computed(() => {
246
+ return props.lists.filter((item: any) => {
247
+ return item.__selected;
248
+ });
249
+ }),
250
+ bulk: computed(() => {
251
+ return props.isHasSelect.map((item: any) => {
252
+ return item.customerId;
253
+ });
254
+ }),
255
+ // 最后一列可见列
256
+ last: 0
257
+ });
258
+
259
+ watch(
260
+ () => props.table,
261
+ () => {
262
+ const _cache = JSON.parse(localStorage.getItem(`${state.name}_table`) || '{}');
263
+ state._last = 0;
264
+ state.table = deepcopy(props.table || [])
265
+ ?.map((item: any, idx: number) => {
266
+ // 缓存的显示信息
267
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_close')) {
268
+ item._close = _cache[item.field]?._close;
269
+ } else {
270
+ if (item.close === true || item.close === 1 || item.close === 'always') {
271
+ item._close = 1;
272
+ }
273
+ }
274
+ // 缓存的排序信息
275
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_sort')) {
276
+ item._sort = _cache[item.field]?._sort;
277
+ }
278
+ if (!item._close) {
279
+ state._last = idx;
280
+ }
281
+ return item;
282
+ })
283
+ .sort((a: any, b: any) => a._sort - b._sort)
284
+ .sort((a: any, b: any) => {
285
+ const fixedOrder: any = { 1: -1, l: -1, r: 1 };
286
+ const aFixed = a.fixed || '';
287
+ const bFixed = b.fixed || '';
288
+ return (fixedOrder[aFixed] || 0) - (fixedOrder[bFixed] || 0);
289
+ });
290
+ },
291
+ {
292
+ deep: true,
293
+ immediate: true
294
+ }
295
+ );
296
+ watch(
297
+ [() => state.table],
298
+ () => {
299
+ const _table: any = {};
300
+ state._last = 0;
301
+ state.table.forEach((item: any, idx: number) => {
302
+ _table[item.field] = { _sort: idx };
303
+ if (Object.prototype.hasOwnProperty.call(item, '_close')) {
304
+ _table[item.field]._close = item._close ? 1 : 0;
305
+ }
306
+ if (!item._close) {
307
+ state._last = idx;
308
+ }
309
+ });
310
+ console.log(338);
311
+ localStorage.setItem(`${state.name}_table`, JSON.stringify(_table));
312
+ },
313
+ { deep: true }
314
+ );
315
+
316
+ // 全选
317
+ const fSelectAll = ({ target = {} }: any = {}) => {
318
+ props.lists.map((item: any = {}) => {
319
+ item.__selected = target.checked;
320
+ });
321
+ };
322
+ const tableRef: any = ref(null);
323
+ onMounted(() => {
324
+ nextTick(() => {
325
+ if (tableRef.value) {
326
+ itable.listen(tableRef.value);
327
+ }
328
+ });
329
+ });
330
+ watch(
331
+ () => state.table,
332
+ () => {
333
+ nextTick(() => {
334
+ itable.listen(tableRef.value);
335
+ });
336
+ },
337
+ {
338
+ deep: true
339
+ }
340
+ );
341
+ onUnmounted(() => {
342
+ itable.remove();
343
+ });
344
+
345
+ // 事件处理
346
+ const event: any = (event: any, data: any): object => {
347
+ const _event: any = {};
348
+ if (isObject(event)) {
349
+ for (const key in event) {
350
+ const fun = event[key];
351
+ if (isFunction(fun)) {
352
+ _event[key] = (...args: any) => {
353
+ return fun({ data, route, router }, ...args);
354
+ };
355
+ }
356
+ }
357
+ }
358
+ return { ..._event };
359
+ };
360
+ </script>
@@ -0,0 +1,2 @@
1
+ import TableLoader from './TableLoader.vue';
2
+ export default TableLoader;