@v2coding/ui 0.1.0 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,236 @@
1
+ <template>
2
+ <div class="ui-field-latlng" v-loading="loading">
3
+ <div class="map"></div>
4
+ <div class="info" v-show="!loading">
5
+ <div class="input-item searchbox">
6
+ <div class="input-item-prepend">
7
+ <span class="input-item-text">搜索关键字</span>
8
+ </div>
9
+ <!-- form="__ignore__" 避免 enter提交表单 -->
10
+ <input ref="input" type="text" form="__ignore__" placeholder="请输入...">
11
+ <div ref="output" class="search-result"></div>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </template>
16
+
17
+ <script>
18
+ import gcoord from 'gcoord';
19
+ import {getAMap} from '../../config/config.amap';
20
+ import FieldMixin from './field.mixin';
21
+
22
+ const CoordTypes = {
23
+ bd09: gcoord.BD09,
24
+ gcj02: gcoord.GCJ02,
25
+ wgs84: gcoord.WGS84,
26
+ };
27
+
28
+ export default {
29
+ name: 'ui-field-latlng',
30
+ mixins: [FieldMixin],
31
+ props: {
32
+ coordType: {
33
+ type: String,
34
+ default: 'wgs84',
35
+ validator: (val) => Object.keys(CoordTypes).includes(val),
36
+ },
37
+ },
38
+ data() {
39
+ return {
40
+ loading: true,
41
+ keyword: '',
42
+ };
43
+ },
44
+ computed: {
45
+ point() {
46
+ if (!this.value) {
47
+ return null;
48
+ }
49
+ if (!this.isValidPoint(this.value)) {
50
+ return null;
51
+ }
52
+ const [lat, lng] = this.value.split(',');
53
+ return {lat: +lat, lng: +lng};
54
+ },
55
+ },
56
+ watch: {
57
+ point(p) {
58
+ this.onPointChange(p);
59
+ },
60
+ },
61
+ methods: {
62
+ init() {
63
+ getAMap(['AMap.ToolBar', 'AMap.Geolocation', 'AMap.AutoComplete']).then((AMap) => {
64
+ this.initMap(AMap);
65
+ this.loading = false;
66
+ this.done();
67
+ });
68
+ },
69
+ initMap(AMap) {
70
+ const map = new AMap.Map(this.$el.querySelector('.map'), {
71
+ zoom: 11,
72
+ });
73
+
74
+ map.addControl(new AMap.ToolBar({position: 'RT'}));
75
+ map.addControl(new AMap.Geolocation({position: 'RB'}));
76
+ const auto = new AMap.AutoComplete({
77
+ input: this.$refs.input,
78
+ output: this.$refs.output,
79
+ });
80
+
81
+ map.on('click', this.onMapClick);
82
+ auto.on('select', (event) => {
83
+ if (!event.poi || !event.poi.location) {
84
+ return;
85
+ }
86
+ map.setZoomAndCenter(16, event.poi.location);
87
+ });
88
+
89
+ this.map = map;
90
+
91
+ this.onPointChange(this.point);
92
+ },
93
+ isValidPoint(val) {
94
+ const [lat, lng] = val.split(',');
95
+ return !(isNaN(+lat) || isNaN(+lng));
96
+ },
97
+ onMapClick({lnglat}) {
98
+ let {lat, lng} = lnglat;
99
+ // 当前地图是 GCJ02 坐标系
100
+ if (this.coordType !== 'gcj02') {
101
+ [lng, lat] = gcoord.transform([lng, lat], gcoord.GCJ02, CoordTypes[this.coordType]);
102
+ lng = lng.toFixed(7) / 1;
103
+ lat = lat.toFixed(7) / 1;
104
+ }
105
+ this.onChange([lat, lng].join(','));
106
+ },
107
+ onPointChange(point) {
108
+ if (!this.map) {
109
+ return;
110
+ }
111
+ this.map.clearMap();
112
+ if (!point) {
113
+ return;
114
+ }
115
+ let {lng, lat} = point;
116
+ // 当前地图是 GCJ02 坐标系
117
+ if (this.coordType !== 'gcj02') {
118
+ [lng, lat] = gcoord.transform([lng, lat], CoordTypes[this.coordType], gcoord.GCJ02);
119
+ }
120
+ // eslint-disable-next-line no-undef
121
+ const marker = new AMap.Marker({position: new AMap.LngLat(lng, lat)});
122
+ this.map.add(marker);
123
+ this.map.setCenter([lng, lat]);
124
+ },
125
+ },
126
+ };
127
+ </script>
128
+
129
+ <style lang="less">
130
+ .ui-field-latlng {
131
+ width: 100%;
132
+ height: 280px;
133
+ position: relative;
134
+
135
+ .map {
136
+ width: 100%;
137
+ height: 100%;
138
+ }
139
+
140
+ .info {
141
+ position: absolute;
142
+ top: 0;
143
+ left: 0;
144
+ right: 0;
145
+ bottom: 0;
146
+ pointer-events: none;
147
+
148
+ .searchbox {
149
+ left: 12px;
150
+ top: 12px;
151
+ background-color: #fff;
152
+ box-shadow: 0 0 3px rgba(0, 0, 0, .5);
153
+ pointer-events: initial;
154
+ border-radius: 3px;
155
+ padding: 3px;
156
+
157
+ .search-result {
158
+ position: absolute;
159
+ top: calc(100% - 2px);
160
+ left: 0;
161
+ right: 0;
162
+ background-color: #fefefe;
163
+ box-shadow: 0 1px 3px #999 ;
164
+ visibility: hidden;
165
+ border-radius: 0 0 3px 3px;
166
+
167
+ .auto-item {
168
+ white-space: nowrap;
169
+ font-size: 12px;
170
+ cursor: pointer;
171
+ padding: 4px;
172
+ line-height: 14px;
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ .input-item {
179
+ position: relative;
180
+ display: inline-flex;
181
+ align-items: center;
182
+ width: 220px;
183
+ font-size: 12px;
184
+
185
+ .input-item-prepend {
186
+ margin-right: -1px;
187
+
188
+ .input-item-text {
189
+ padding: 0.25em 0.5em;
190
+ display: block;
191
+ text-justify: distribute-all-lines;
192
+ text-align-last: justify;
193
+ align-items: center;
194
+ margin-bottom: 0;
195
+ font-weight: 400;
196
+ line-height: 1.5;
197
+ color: #495057;
198
+ text-align: center;
199
+ white-space: nowrap;
200
+ background-color: #e9ecef;
201
+ border: 1px solid #ced4da;
202
+ border-radius: .25rem 0 0 .25rem;
203
+ box-sizing: border-box;
204
+ }
205
+ }
206
+
207
+ input {
208
+ position: relative;
209
+ flex: 1 1 auto;
210
+ width: 1%;
211
+ margin: 0;
212
+ background: #fff;
213
+ padding: 0.25em 0.5em;
214
+ display: inline-block;
215
+ line-height: 1.5;
216
+ color: #495057;
217
+ vertical-align: middle;
218
+ border: 1px solid #ced4da;
219
+ border-radius: 0 .25rem .25rem 0;
220
+ appearance: none;
221
+ box-sizing: border-box;
222
+
223
+ &:focus {
224
+ border-color: #80bdff;
225
+ outline: 0;
226
+ box-shadow: 0 0 0 0.1rem rgba(128, 189, 255, .1);
227
+ }
228
+ }
229
+ }
230
+
231
+ .amap-logo,
232
+ .amap-copyright {
233
+ display: none !important;
234
+ }
235
+ }
236
+ </style>
@@ -11,7 +11,6 @@
11
11
  import 'quill/dist/quill.snow.css';
12
12
  import 'quill/dist/quill.bubble.css';
13
13
  import Objects from '../../util/objects';
14
- import {addFieldType} from '../form/form.field';
15
14
 
16
15
  const Font = Quill.import('formats/font');
17
16
 
@@ -77,15 +76,6 @@
77
76
  },
78
77
  };
79
78
 
80
- /**
81
- * ui-form-item 添加 type="rich" 支持
82
- */
83
- const attachToFormItem = () => {
84
- addFieldType('rich', RichField);
85
- };
86
-
87
- RichField.attachToFormItem = attachToFormItem;
88
-
89
79
  export default RichField;
90
80
  </script>
91
81
 
@@ -152,9 +152,6 @@ export default {
152
152
  },
153
153
  methods: {
154
154
  registeredField () {
155
- if (this.ignore) {
156
- return;
157
- }
158
155
  this.uiForm.addField(this.name, this.fieldValue, this);
159
156
  },
160
157
  resetField (...args) {
@@ -8,6 +8,8 @@
8
8
  <script>
9
9
  import throttle from 'lodash.throttle';
10
10
  import Objects from '../../util/objects';
11
+ import FormItem from './form.item';
12
+ import TableSelectItem from '../table/table.select.item';
11
13
 
12
14
  export default {
13
15
  name: 'ui-form',
@@ -59,8 +61,6 @@
59
61
  fieldList: [],// [[name, value], ...]
60
62
  };
61
63
  },
62
- created() {
63
- },
64
64
  computed: {
65
65
  model() {
66
66
  return Object.fromEntries(this.fieldList);
@@ -71,7 +71,11 @@
71
71
  return listeners;
72
72
  },
73
73
  },
74
+ beforeCreate() {
75
+ this.isMounted = false;
76
+ },
74
77
  mounted() {
78
+ this.isMounted = true;
75
79
  this.$el.addEventListener('reset', this.onReset);
76
80
  this.checkFieldsReady();
77
81
  },
@@ -104,11 +108,12 @@
104
108
  if (!Objects.isObject(values)) {
105
109
  values = {};
106
110
  }
107
- this.fieldList.slice().forEach(([name, , field]) => {
108
- if (Object.prototype.hasOwnProperty.call(values, name)) {
109
- field.resetField(values[name]);
111
+ const formItems = this.getFormItems();
112
+ formItems.forEach(item => {
113
+ if (Object.prototype.hasOwnProperty.call(values, item.name)) {
114
+ item.resetField(values[item.name]);
110
115
  } else {
111
- field.resetField();
116
+ item.resetField();
112
117
  }
113
118
  });
114
119
  },
@@ -119,19 +124,40 @@
119
124
  if (!values || !Objects.isObject(values)) {
120
125
  return;
121
126
  }
127
+ const formItems = this.getFormItems();
122
128
  Object.entries(values).forEach(([fieldName, fieldValue]) => {
123
- const fieldItem = this.fieldList.find(([name]) => name === fieldName);
129
+ const fieldItem = formItems.find(item => item.name === fieldName);
124
130
  if (!fieldItem) {
125
131
  return;
126
132
  }
127
- fieldItem[2].fieldValue = fieldValue;
133
+ fieldItem.fieldValue = fieldValue;
128
134
  });
129
135
  },
130
136
  /**
131
137
  * @public
132
138
  */
133
139
  getValues() {
134
- return Object.fromEntries(this.fieldList);
140
+ const formItems = this.getFormItems();
141
+ return formItems.reduce((values, item) => {
142
+ if (item.ignore === true) {
143
+ return values;
144
+ }
145
+ return {...values, [item.name]: item.fieldValue};
146
+ }, {});
147
+ },
148
+ getFormItems() {
149
+ const listSearchItem = (items) => {
150
+ return items.reduce((results, item) => {
151
+ // TableSelectItem mixins FormItem
152
+ if ([FormItem.name, TableSelectItem.name].includes(item.$options.name)) {
153
+ results.push(item);
154
+ } else {
155
+ results.push(...listSearchItem(item.$children || []));
156
+ }
157
+ return results;
158
+ }, []);
159
+ };
160
+ return listSearchItem(this.$children);
135
161
  },
136
162
  /**
137
163
  * @private
@@ -207,31 +233,14 @@
207
233
  }
208
234
  this[`onField${e}`](...args);
209
235
  },
210
- getAllFields() {
211
- const getFormFields = (components) => {
212
- if (!Array.isArray(components) || !components.length) {
213
- return [];
214
- }
215
- return components.reduce((total, component) => {
216
- // ui-table-select-item mixins ui-form-item
217
- if (['ui-form-item', 'ui-table-select-item'].includes(component.$options.name)) {
218
- !component.ignore && component.name && total.push(component.name);
219
- } else {
220
- total.push(...getFormFields(component.$children));
221
- }
222
- return total;
223
- }, []);
224
- };
225
- this.formFields = getFormFields(this.$children);
226
- return this.formFields;
227
- },
228
236
  /**
229
237
  * @private
230
238
  */
231
239
  onFieldPending(component) {
232
- if(component.name) {
233
- this.fieldStatus.push({name: component.name, status: false, instance: component});
240
+ if (!component.name) {
241
+ return;
234
242
  }
243
+ this.fieldStatus.push({name: component.name, status: false, instance: component});
235
244
  },
236
245
  /**
237
246
  * @private
@@ -244,8 +253,8 @@
244
253
  const i = this.fieldList.findIndex(item => item[0] === component.name);
245
254
  this.fieldList.splice(i, 1);
246
255
  }
247
- const formFields = this.getAllFields();
248
- if (formFields.length === this.fieldStatus.length) {
256
+ const formItems = this.getFormItems();
257
+ if (formItems.length === this.fieldStatus.length) {
249
258
  this.checkFieldsReady();
250
259
  }
251
260
  },
@@ -257,13 +266,9 @@
257
266
  return;
258
267
  }
259
268
  const index = this.fieldStatus.findIndex(item => item.name === component.name);
260
- if (index === -1) {
261
- this.fieldStatus.push({name: component.name, status: true, instance: component});
262
- } else {
263
- this.fieldStatus.splice(index, 1, {name: component.name, status: true, instance: component});
264
- }
265
- const formFields = this.getAllFields();
266
- if (formFields.length === this.fieldStatus.length) {
269
+ index !== -1 && this.fieldStatus.splice(index, 1, {name: component.name, status: true, instance: component});
270
+ const formItems = this.getFormItems();
271
+ if (formItems.length === this.fieldStatus.length) {
267
272
  this.checkFieldsReady();
268
273
  }
269
274
  },
@@ -277,8 +282,12 @@
277
282
  }
278
283
  },
279
284
  checkFieldsReady() {
285
+ if (!this.isMounted) {
286
+ return;
287
+ }
280
288
  const isPending = this.fieldStatus.some(item => !item.status);
281
- if (!isPending) {
289
+ if (!isPending && !this.isReady) {
290
+ this.isReady = true;
282
291
  this.$emit('ready');
283
292
  }
284
293
  },
@@ -16,7 +16,7 @@
16
16
  import MenuItem from './menu-item';
17
17
 
18
18
  export default {
19
- name: 'head-menu',
19
+ name: 'ui-head-menu',
20
20
  components: {MenuItem},
21
21
  provide() {
22
22
  return {
@@ -31,20 +31,16 @@
31
31
  return ['nav-menu-submenu-popup', this.theme].join(' ');
32
32
  },
33
33
  },
34
- render() {
34
+ render(createElement) {
35
35
  if (this.isLeaf) {
36
- return (
37
- <el-menu-item index={this.index} route={this.route}>
38
- <template slot="title">{this.item.name}</template>
39
- </el-menu-item>
40
- );
36
+ return createElement('el-menu-item', {props: {index: this.index, route: this.route}}, [
37
+ createElement('template', {slot: 'title'}, [this.item.name]),
38
+ ]);
41
39
  }
42
- return (
43
- <el-submenu index={this.index} popperClass={this.popperClass} popper-append-to-body={false}>
44
- <template slot="title">{this.item.name}</template>
45
- {this.item.children.map(child => <head-menu-submenu key={child.id} item={child}/>)}
46
- </el-submenu>
47
- );
40
+ return createElement('el-submenu', {props: {index: this.index, popperClass: this.popperClass, popperAppendToBody: false}}, [
41
+ createElement('template', {slot: 'title'}, [this.item.name]),
42
+ ...this.item.children.map(child => createElement('head-menu-submenu', {key: child.id, props: {item: child}})),
43
+ ]);
48
44
  },
49
45
  };
50
46
  </script>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="history" v-show="visible">
3
- <scroll-nav ref="menus" class="history-tabs">
3
+ <scroll-view ref="menus" class="history-tabs">
4
4
  <div
5
5
  v-for="item in items"
6
6
  :key="item.path"
@@ -10,7 +10,7 @@
10
10
  <span class="ellipsis" :title="item.title">{{ item.title }}</span>
11
11
  <i class="el-icon-close" @click.stop="onTabRemove(item.path)"></i>
12
12
  </div>
13
- </scroll-nav>
13
+ </scroll-view>
14
14
  <div class="contextmenu" :style="contextmenu">
15
15
  <div
16
16
  class="modal"
@@ -54,8 +54,11 @@
54
54
  </template>
55
55
 
56
56
  <script>
57
+ import ScrollView from '../scroll-view/scroll-view';
58
+
57
59
  export default {
58
- name: "History",
60
+ name: "ui-history",
61
+ components: {ScrollView},
59
62
  props: {
60
63
  items: Array,
61
64
  current: null,
@@ -106,7 +109,7 @@ export default {
106
109
  this.$emit("remove-history", { type: "current", name: path });
107
110
  },
108
111
  onContextMenu(event) {
109
- const container = this.$el.querySelector(".scroll-nav__nav");
112
+ const container = this.$el.querySelector(".ui-scroll-view__nav");
110
113
  const index = this.getChildContainIndex(container, event.target);
111
114
  const rect = this.$el.getBoundingClientRect();
112
115
  if (index !== -1) {
@@ -159,15 +162,13 @@ export default {
159
162
  </script>
160
163
 
161
164
  <style lang="scss">
162
- @import "../../assets/style/var";
163
-
164
165
  .history {
165
166
  flex: none;
166
167
  height: 40px;
167
168
  position: relative;
168
169
  margin: 10px 0 0;
169
170
 
170
- .history-tabs.scroll-nav__nav-wrap {
171
+ .history-tabs.ui-scroll-view__nav-wrap {
171
172
  left: 0;
172
173
  right: 0;
173
174
  top: 0;
@@ -175,11 +176,11 @@ export default {
175
176
  position: absolute;
176
177
  align-items: flex-end;
177
178
 
178
- .scroll-nav__nav-scroll {
179
+ .ui-scroll-view__nav-scroll {
179
180
  flex: 1;
180
181
  }
181
182
 
182
- .scroll-nav__nav-control {
183
+ .ui-scroll-view__nav-control {
183
184
  width: 20px;
184
185
  height: 30px;
185
186
 
@@ -193,7 +194,7 @@ export default {
193
194
  }
194
195
  }
195
196
 
196
- .scroll-nav__nav {
197
+ .ui-scroll-view__nav {
197
198
  align-items: flex-end;
198
199
  }
199
200
 
@@ -37,7 +37,7 @@ export default {
37
37
  };
38
38
  </script>
39
39
 
40
- <style scoped>
40
+ <style lang="less" scoped>
41
41
  .ui-icon {
42
42
  width: 1em;
43
43
  height: 1em;
@@ -45,10 +45,10 @@ export default {
45
45
  fill: currentColor;
46
46
  overflow: hidden;
47
47
  display: inline-block;
48
- }
49
48
 
50
- .ui-icon.ui-icon-loading {
51
- animation: rotating 2s linear infinite;
49
+ &.ui-icon-loading {
50
+ animation: rotating 2s linear infinite;
51
+ }
52
52
  }
53
53
 
54
54
  @keyframes rotating {
@@ -9,7 +9,7 @@
9
9
 
10
10
  <script>
11
11
  export default {
12
- name: 'minimize',
12
+ name: 'ui-minimize',
13
13
  props: {
14
14
  direction: {
15
15
  validator: (val) => ['top', 'right', 'bottom', 'left'].indexOf(val) !== -1,