@v2coding/ui 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 (49) hide show
  1. package/README.md +6 -0
  2. package/dist/v2coding-ui.esm.js +10840 -0
  3. package/dist/v2coding-ui.min.js +1 -0
  4. package/dist/v2coding-ui.ssr.js +10747 -0
  5. package/package.json +54 -0
  6. package/src/components/dialog/dialog.vue +179 -0
  7. package/src/components/drawer/drawer.vue +523 -0
  8. package/src/components/exports/index.vue +53 -0
  9. package/src/components/exports/remote-exports-dialog.vue +202 -0
  10. package/src/components/field/field.autocomplete.vue +21 -0
  11. package/src/components/field/field.calendar.vue +117 -0
  12. package/src/components/field/field.cascade.vue +233 -0
  13. package/src/components/field/field.checkbox.vue +134 -0
  14. package/src/components/field/field.color.vue +24 -0
  15. package/src/components/field/field.date.vue +145 -0
  16. package/src/components/field/field.icons.vue +123 -0
  17. package/src/components/field/field.number.vue +43 -0
  18. package/src/components/field/field.radio.vue +100 -0
  19. package/src/components/field/field.rate.vue +37 -0
  20. package/src/components/field/field.rich.vue +165 -0
  21. package/src/components/field/field.select.vue +210 -0
  22. package/src/components/field/field.slider.vue +66 -0
  23. package/src/components/field/field.switch.vue +14 -0
  24. package/src/components/field/field.text.vue +66 -0
  25. package/src/components/field/field.timepicker.vue +70 -0
  26. package/src/components/field/field.timeselect.vue +24 -0
  27. package/src/components/field/field.trigger.dialog.vue +50 -0
  28. package/src/components/field/field.trigger.popover.vue +63 -0
  29. package/src/components/field/field.upload.file.vue +241 -0
  30. package/src/components/field/field.upload.image.vue +125 -0
  31. package/src/components/field/field.upload.portrait.vue +304 -0
  32. package/src/components/fill-view/index.vue +43 -0
  33. package/src/components/form/form.dialog.vue +174 -0
  34. package/src/components/form/form.drawer.vue +246 -0
  35. package/src/components/form/form.fieldset.vue +110 -0
  36. package/src/components/form/form.item.vue +213 -0
  37. package/src/components/form/form.vue +293 -0
  38. package/src/components/head-menu/index.vue +188 -0
  39. package/src/components/head-menu/menu-item.vue +84 -0
  40. package/src/components/history/index.vue +360 -0
  41. package/src/components/icon/icon.vue +63 -0
  42. package/src/components/minimize/index.vue +342 -0
  43. package/src/components/page/page.vue +43 -0
  44. package/src/components/provider/provider.vue +15 -0
  45. package/src/components/scroll-view/scroll-view.vue +384 -0
  46. package/src/components/table/column.vue +262 -0
  47. package/src/components/table/table.pagination.vue +71 -0
  48. package/src/components/table/table.select.vue +165 -0
  49. package/src/components/table/table.vue +805 -0
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <el-color-picker v-bind="$attrs" v-on="$listeners" :value="value" :show-alpha="showAlpha" class="ui-field-color"></el-color-picker>
3
+ </template>
4
+
5
+ <script>
6
+ import FieldMixin from './field.mixin';
7
+
8
+ export default {
9
+ name: 'ui-field-color',
10
+ mixins: [FieldMixin],
11
+ props: {
12
+ showAlpha: {
13
+ type: Boolean,
14
+ default: true,
15
+ },
16
+ },
17
+ };
18
+ </script>
19
+
20
+ <style scoped>
21
+ .ui-field-color {
22
+ width: 100%;
23
+ }
24
+ </style>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <el-date-picker
3
+ v-bind="$attrs"
4
+ v-on="_listeners"
5
+ :value="pickerValue"
6
+ :type="type"
7
+ :format="format"
8
+ :value-format="valueFormat"
9
+ :start-placeholder="startPlaceholder"
10
+ :end-placeholder="endPlaceholder"
11
+ :picker-options="realPickerOptions"
12
+ @input="onChange"
13
+ class="ui-date-field"
14
+ />
15
+ </template>
16
+
17
+ <script>
18
+ import FieldMixin from './field.mixin';
19
+ import {DisabledDate, Shortcuts} from './field.date.picker-options';
20
+
21
+ export default {
22
+ name: 'ui-field-date',
23
+ mixins: [FieldMixin],
24
+ props: {
25
+ type: {
26
+ type: String,
27
+ default: 'date',
28
+ },
29
+ format: {
30
+ type: String,
31
+ default() {
32
+ switch (this.type) {
33
+ case 'year':
34
+ return 'yyyy';
35
+ case 'month':
36
+ case 'monthrange':
37
+ return 'yyyy-MM';
38
+ case 'week':
39
+ return 'yyyy-WW';
40
+ case 'datetime':
41
+ case 'datetimerange':
42
+ return 'yyyy-MM-dd HH:mm:ss';
43
+ default:
44
+ return 'yyyy-MM-dd';
45
+ }
46
+ },
47
+ },
48
+ valueFormat: {
49
+ type: String,
50
+ default() {
51
+ return this.format;
52
+ },
53
+ },
54
+ startPlaceholder: {
55
+ type: String,
56
+ default: '请选择开始时间',
57
+ },
58
+ endPlaceholder: {
59
+ type: String,
60
+ default: '请选择结束时间',
61
+ },
62
+ pickerOptions: {
63
+ type: Object,
64
+ },
65
+ shortcuts: {
66
+ type: String,
67
+ default() {
68
+ if (this.type === 'date') {
69
+ return 'today,yesterday,lastMonth';
70
+ }
71
+ return '';
72
+ }
73
+ },
74
+ disabledDate: {
75
+ type: String,
76
+ validator: (val) => ['before', 'after'].includes(val),
77
+ },
78
+ },
79
+ computed: {
80
+ pickerValue() {
81
+ return this.getPickerValue(this.value);
82
+ },
83
+ realPickerOptions() {
84
+ if (this.pickerOptions) {
85
+ return this.pickerOptions;
86
+ }
87
+ const options = {};
88
+ if (this.shortcuts) {
89
+ const shortcuts = [];
90
+ this.shortcuts.split(',').reduce((prev, shortcut) => {
91
+ const sc = Shortcuts[shortcut];
92
+ if (sc) {
93
+ prev.push(sc);
94
+ }
95
+ return prev;
96
+ }, shortcuts);
97
+ shortcuts.length > 0 && (options.shortcuts = shortcuts);
98
+ }
99
+ if (this.disabledDate) {
100
+ const disabledDate = DisabledDate[this.disabledDate];
101
+ disabledDate && (options.disabledDate = disabledDate);
102
+ }
103
+ return options;
104
+ },
105
+ },
106
+ methods: {
107
+ getPickerValue(value) {
108
+ switch (this.type) {
109
+ case 'dates':
110
+ case 'daterange':
111
+ case 'monthrange':
112
+ case 'datetimerange':
113
+ return value ? value.split(',') : [];
114
+ default:
115
+ return value;
116
+ }
117
+ },
118
+ getRealValue(value) {
119
+ switch (this.type) {
120
+ case 'dates':
121
+ case 'daterange':
122
+ case 'monthrange':
123
+ case 'datetimerange':
124
+ return value ? value.join(',') : '';
125
+ default:
126
+ return value || '';
127
+ }
128
+ },
129
+ onChange(value) {
130
+ const _value = this.getRealValue(value);
131
+ this.emitChange(_value);
132
+ },
133
+ focus() {
134
+ const datepicker = this.$children[0];
135
+ datepicker && datepicker.focus();
136
+ },
137
+ },
138
+ };
139
+ </script>
140
+
141
+ <style lang="less" scoped>
142
+ .ui-date-field.el-date-editor {
143
+ width: 100%;
144
+ }
145
+ </style>
@@ -0,0 +1,123 @@
1
+ <template>
2
+ <trigger-field popover v-bind="$attrs" :value="value" :visible.sync="visible" :prefix-icon="value" @hide="onHide">
3
+ <div class="ui-field-icons">
4
+ <el-input class="filter" v-model="filter" placeholder="输入名称快速查找" clearable/>
5
+ <div class="scroll">
6
+ <div class="icons" v-loading="iconsLoading">
7
+ <div v-for="icon in filteredIcons" :key="icon" class="icon" :class="{active: value === icon}" :title="icon" @click="sel(icon)">
8
+ <icon :name="icon"/>
9
+ <span class="ellipsis">{{ icon }}</span>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ </div>
14
+ </trigger-field>
15
+ </template>
16
+
17
+ <script>
18
+ import Icon from '../icon/icon';
19
+ import FieldMixin from './field.mixin';
20
+ import TriggerField from './field.trigger';
21
+ import Iconfont from '../../config/config.iconfont';
22
+
23
+ export default {
24
+ name: 'ui-field-icons',
25
+ mixins: [FieldMixin],
26
+ components: {Icon, TriggerField},
27
+ data() {
28
+ return {
29
+ filter: '',
30
+ icons: [],
31
+ iconsLoading: false,
32
+ visible: false,
33
+ };
34
+ },
35
+ computed: {
36
+ filteredIcons() {
37
+ return this.icons.filter((icon) => icon.toLowerCase().indexOf(String(this.filter).toLowerCase()) !== -1);
38
+ },
39
+ },
40
+ mounted() {
41
+ this.initIcons();
42
+ },
43
+ methods: {
44
+ async initIcons() {
45
+ this.iconsLoading = true;
46
+ const icons = await Iconfont.getIcons();
47
+ this.iconsLoading = false;
48
+ this.icons = icons;
49
+ },
50
+ onChange(val) {
51
+ this.$emit('input', val);
52
+ this.$emit('change', val);
53
+ },
54
+ sel(icon) {
55
+ this.onChange(icon);
56
+ this.visible = false;
57
+ },
58
+ onHide() {
59
+ this.filter = '';
60
+ },
61
+ focus() {
62
+ this.visible = true;
63
+ },
64
+ },
65
+ };
66
+ </script>
67
+
68
+ <style lang="less" scoped>
69
+ .ui-field-icons {
70
+ .filter {
71
+ margin-bottom: 10px;
72
+
73
+ ::v-deep .el-input__validateIcon {
74
+ display: none;
75
+ }
76
+ }
77
+
78
+ .scroll {
79
+ height: 200px;
80
+ overflow: auto;
81
+ }
82
+
83
+ .icons {
84
+ display: flex;
85
+ flex-wrap: wrap;
86
+
87
+ .icon {
88
+ flex: none;
89
+ width: 150px;
90
+ height: 28px;
91
+ margin: 2px;
92
+ padding: 4px;
93
+ border-radius: 2px;
94
+ cursor: pointer;
95
+ transition: all 0.3s;
96
+ overflow: hidden;
97
+ text-overflow: ellipsis;
98
+ white-space: nowrap;
99
+ display: flex;
100
+ flex-direction: row;
101
+ align-items: center;
102
+
103
+ &:hover {
104
+ background: #eaeaea;
105
+ }
106
+
107
+ &.active {
108
+ color: #409eff;
109
+ box-shadow: inset 0 0 3px #666;
110
+ }
111
+
112
+ .ui-icon {
113
+ margin-right: 4px;
114
+ }
115
+
116
+ span {
117
+ flex: 1;
118
+
119
+ }
120
+ }
121
+ }
122
+ }
123
+ </style>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <el-input-number v-bind="$attrs" v-on="$listeners" :value="pickerValue" class="ui-number-field" :controls-position="controlsPosition" />
3
+ </template>
4
+
5
+ <script>
6
+ import FieldMixin from './field.mixin';
7
+
8
+ export default {
9
+ name: 'ui-field-number',
10
+ mixins: [FieldMixin],
11
+ props: {
12
+ controlsPosition: {
13
+ type: String,
14
+ default: 'right',
15
+ },
16
+ },
17
+ computed: {
18
+ pickerValue() {
19
+ const v = [null, undefined, ''].includes(this.value) ? undefined : +this.value;
20
+ if (isNaN(v)) {
21
+ return undefined;
22
+ }
23
+ return v;
24
+ },
25
+ },
26
+ methods: {
27
+ focus() {
28
+ const numberInput = this.$children[0];
29
+ numberInput && numberInput.focus();
30
+ },
31
+ }
32
+ };
33
+ </script>
34
+
35
+ <style lang="less" scoped>
36
+ .ui-number-field {
37
+ width: 100%;
38
+
39
+ ::v-deep input {
40
+ text-align: initial;
41
+ }
42
+ }
43
+ </style>
@@ -0,0 +1,100 @@
1
+ <template>
2
+ <div class="ui-field-radio" v-loading="realLoading" element-loading-spinner="el-icon-loading">
3
+ <el-radio-group v-bind="$attrs" v-on="$listeners" :value="value">
4
+ <component v-bind:is="optionComponent" v-bind="item" v-for="item in realData" :key="item.value" :label="item.value" :border="ui === 'border'" :title="item.label">
5
+ {{ item.label }}
6
+ </component>
7
+ </el-radio-group>
8
+ <div v-if="isEmpty" class="empty">暂无数据!&emsp;<el-button v-show="realError" type="text" @click="init">重新加载</el-button>
9
+ </div>
10
+ </div>
11
+ </template>
12
+
13
+ <script>
14
+ import FieldMixin from './field.mixin';
15
+ import DataMixin from './field.data.mixin';
16
+ import Objects from '../../util/objects';
17
+
18
+ export default {
19
+ name: 'ui-field-radio',
20
+ mixins: [FieldMixin, DataMixin],
21
+ props: {
22
+ ui: {
23
+ type: String,
24
+ validator: (val) => ['default', 'border', 'button'].includes(val),
25
+ },
26
+ initDefault: {
27
+ type: Boolean,
28
+ default: true,
29
+ },
30
+ },
31
+ computed: {
32
+ optionComponent() {
33
+ if (this.ui === 'button') {
34
+ return 'el-radio-button';
35
+ }
36
+ return 'el-radio';
37
+ },
38
+ isEmpty() {
39
+ return !this.realData.length;
40
+ },
41
+ },
42
+ watch: {
43
+ realData(data, o) {
44
+ if (!Objects.isEquals(data, o)) {
45
+ this.initDefaultValue();
46
+ }
47
+ },
48
+ },
49
+ methods: {
50
+ init() {
51
+ this.getData().then(() => {
52
+ this.done();
53
+ this.initDefaultValue();
54
+ });
55
+ },
56
+ initDefaultValue() {
57
+ if (!this.initDefault) {
58
+ return;
59
+ }
60
+ if (this.hasMatched()) {
61
+ return;
62
+ }
63
+ const first = this.realData.find(Boolean);
64
+ first && this.onChange(first.value);
65
+ },
66
+ hasMatched() {
67
+ return this.realData.some((item) => Object.is(item.value, this.value));
68
+ },
69
+ resetValue() {
70
+ this.onChange('');
71
+ },
72
+ },
73
+ };
74
+ </script>
75
+
76
+ <style lang="less" scoped>
77
+ .ui-field-radio {
78
+ .empty {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ font-size: 12px;
82
+ color: #909399;
83
+ }
84
+
85
+ > .el-radio-group {
86
+ display: inline-flex;
87
+ flex-direction: row;
88
+ flex-wrap: wrap;
89
+ align-items: center;
90
+
91
+ .el-radio {
92
+ line-height: 36px;
93
+ }
94
+ }
95
+ }
96
+
97
+ ::v-deep .el-loading-mask .el-loading-spinner {
98
+ margin-top: -14px;
99
+ }
100
+ </style>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <el-rate v-bind="$attrs" v-on="_listeners" v-model="score" :max="max"></el-rate>
3
+ </template>
4
+
5
+ <script>
6
+ import FieldMixin from './field.mixin';
7
+
8
+ export default {
9
+ name: 'ui-field-rate',
10
+ mixins: [FieldMixin],
11
+ props: {
12
+ max: {
13
+ type: Number,
14
+ default: 5,
15
+ },
16
+ },
17
+ computed: {
18
+ score: {
19
+ get() {
20
+ if (!this.value) {
21
+ return 0;
22
+ }
23
+ const num = Number(this.value);
24
+ if (isNaN(num)) {
25
+ return 0;
26
+ }
27
+ return Math.min(num, this.max);
28
+ },
29
+ set(v) {
30
+ this.onChange(v);
31
+ }
32
+ },
33
+ },
34
+ };
35
+ </script>
36
+
37
+ <style scoped></style>
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <quill-editor :content="value" :options="realOptions" @change="onChange"></quill-editor>
3
+ </template>
4
+
5
+ <script>
6
+ import {Message} from 'element-ui';
7
+ import {Quill, quillEditor} from 'vue-quill-editor';
8
+ import FieldMixin from './field.mixin';
9
+ import {quillRedefine} from './field.rich.upload';
10
+ import 'quill/dist/quill.core.css';
11
+ import 'quill/dist/quill.snow.css';
12
+ import 'quill/dist/quill.bubble.css';
13
+ import Objects from '../../util/objects';
14
+ import {addFieldType} from '../form/form.field';
15
+
16
+ const Font = Quill.import('formats/font');
17
+
18
+ Font.whitelist = ['Arial', 'FangSong', 'HeiTi', 'Microsoft'];
19
+
20
+ Quill.register(Font, true);
21
+
22
+ const defaultConfig = {
23
+ upload: {
24
+ url: ({type}) => (type === 'oss' ? '/aliyun/oss' : '/api/oss/upload'), // 必填参数 图片上传地址
25
+ accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon', // 可选 可上传的图片格式
26
+ filename: 'file', // 必填参数 文件的参数名
27
+ type: 'oss', // default:上传至服务器; oss:上传至oss
28
+ afterUpload(result) {
29
+ if (!result.success) {
30
+ Message.error(result.message || '上传错误');
31
+ return;
32
+ }
33
+ return result.content.url;
34
+ },
35
+ beforeUpload: () => void 0,
36
+ },
37
+ placeholder: '请输入...',
38
+ theme: 'snow', // 主题
39
+ modules: {
40
+ toolbar: {
41
+ // 工具栏选项
42
+ container: [
43
+ ['bold', 'italic', 'underline', 'strike'],
44
+ ['blockquote', 'code-block'],
45
+ [{header: 1}, {header: 2}],
46
+ [{list: 'ordered'}, {list: 'bullet'}],
47
+ [{script: 'sub'}, {script: 'super'}],
48
+ [{indent: '-1'}, {indent: '+1'}],
49
+ [{direction: 'rtl'}],
50
+ [{size: ['small', false, 'large', 'huge']}],
51
+ [{header: [1, 2, 3, 4, 5, 6, false]}],
52
+ [{color: []}, {background: []}],
53
+ [{font: ['Arial', 'FangSong', 'HeiTi', 'Microsoft']}],
54
+ [{align: []}],
55
+ ['clean'],
56
+ ['link', 'image', 'video'],
57
+ ],
58
+ },
59
+ },
60
+ };
61
+
62
+ const RichField = {
63
+ name: 'ui-field-rich',
64
+ mixins: [FieldMixin],
65
+ components: {
66
+ quillEditor,
67
+ },
68
+ computed: {
69
+ realOptions() {
70
+ return quillRedefine(Objects.merge({}, defaultConfig, this.$attrs));
71
+ },
72
+ },
73
+ methods: {
74
+ onChange({html}) {
75
+ this.emitChange(html);
76
+ },
77
+ },
78
+ };
79
+
80
+ /**
81
+ * ui-form-item 添加 type="rich" 支持
82
+ */
83
+ const attachToFormItem = () => {
84
+ addFieldType('rich', RichField);
85
+ };
86
+
87
+ RichField.attachToFormItem = attachToFormItem;
88
+
89
+ export default RichField;
90
+ </script>
91
+
92
+ <style lang="less">
93
+ .quill-editor {
94
+ /*工具栏内用*/
95
+
96
+ .ql-font {
97
+ span[data-value="Arial"]::before {
98
+ content: "Arial" !important;
99
+ font-family: "Arial",serif;
100
+ }
101
+
102
+ span[data-value="FangSong"]::before {
103
+ content: "仿宋" !important;
104
+ font-family: "仿宋_GB2312", "FangSong_GB2312", "宋体", "SimSun", "STFangsong","STSong", serif;
105
+ }
106
+
107
+ span[data-value="HeiTi"]::before {
108
+ content: "黑体" !important;
109
+ font-family: "黑体", "SimHei", "微软正黑体", "Microsoft JhengHei", "STHeiti",serif;
110
+ }
111
+
112
+ span[data-value="Microsoft"]::before {
113
+ content: "微软雅黑" !important;
114
+ font-family: "微软雅黑", "Microsoft YaHei",serif;
115
+ }
116
+ }
117
+
118
+ /*编辑器内容用*/
119
+
120
+ .ql-font-Arial {
121
+ font-family: "Arial",serif;
122
+ }
123
+
124
+ .ql-font-FangSong {
125
+ font-family: "仿宋_GB2312", "FangSong_GB2312", "宋体", "SimSun", "STFangsong","STSong", serif;
126
+ }
127
+
128
+ .ql-font-HeiTi {
129
+ font-family: "黑体", "SimHei", "微软正黑体", "Microsoft JhengHei", "STHeiti",serif;
130
+ }
131
+
132
+ .ql-font-Microsoft {
133
+ font-family: "微软雅黑", "Microsoft YaHei",serif;
134
+ }
135
+ }
136
+ </style>
137
+
138
+ <style lang="less" scoped>
139
+ .quill-editor {
140
+ width: 100%;
141
+
142
+ display: flex;
143
+ align-items: initial !important;
144
+ flex-direction: column;
145
+
146
+ .ql-toolbar {
147
+ flex: none;
148
+ }
149
+
150
+ .ql-container {
151
+ flex: auto;
152
+ height: initial;
153
+ display: flex;
154
+ flex-direction: column;
155
+
156
+ .ql-editor {
157
+ flex: auto;
158
+ }
159
+ }
160
+ }
161
+
162
+ .quill-editor ::v-deep .ql-editor {
163
+ min-height: 200px;
164
+ }
165
+ </style>