free-fe-core-modules 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Basic/BreadCrumbs.vue +18 -9
- package/components/Basic/LeveledMenus.vue +13 -5
- package/components/Basic/SummaryHead.vue +5 -2
- package/components/Dialog/BasicDialog.vue +14 -3
- package/components/FloatingWindow/index.vue +9 -1
- package/components/SlidingCarousel/index.vue +5 -2
- package/components/SlidingNews/index.vue +33 -24
- package/composible/useFormValidator.js +56 -0
- package/free-field/Fields/AgreementCheck.js +6 -2
- package/free-field/Fields/Category.js +2 -1
- package/free-field/Fields/Check.js +1 -0
- package/free-field/Fields/Date.js +13 -5
- package/free-field/Fields/DateRange.js +14 -8
- package/free-field/Fields/DynamicList.js +36 -33
- package/free-field/Fields/FixedList.vue +9 -5
- package/free-field/Fields/Labels.vue +7 -1
- package/free-field/Fields/MixedTable.vue +9 -3
- package/free-field/Fields/Number.js +12 -6
- package/free-field/Fields/Password.js +12 -6
- package/free-field/Fields/Search.vue +8 -2
- package/free-field/Fields/Select.vue +4 -1
- package/free-field/Fields/SelectionChain.vue +8 -2
- package/free-field/Fields/String.js +11 -5
- package/free-field/Fields/Text.js +12 -6
- package/free-field/Fields/Time.vue +8 -2
- package/free-field/Fields/TimeRange.vue +13 -5
- package/free-field/Fields/Year.js +12 -6
- package/free-field/Fields/YearRange.vue +9 -6
- package/free-field/composible/fieldWrapper.js +59 -51
- package/free-field/composible/freeFieldLabel.js +10 -3
- package/index.js +123 -78
- package/package.json +1 -1
- package/view/dict/index.vue +85 -1
- package/view/menu/index.vue +15 -11
- package/view/mourning/mourning.vue +17 -12
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
:options="minYearOptions"
|
|
20
20
|
:readonly="Field.ReadOnly"
|
|
21
21
|
@input="rangeChanged"
|
|
22
|
-
|
|
22
|
+
ref="input_field_validator_first"
|
|
23
23
|
>
|
|
24
24
|
<template v-slot:before v-if="Field.Label !== void 0">
|
|
25
25
|
<span
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
:options="maxYearOptions"
|
|
40
40
|
:readonly="Field.ReadOnly"
|
|
41
41
|
@input="rangeChanged"
|
|
42
|
-
|
|
42
|
+
ref="input_field_validator_second"
|
|
43
43
|
/>
|
|
44
44
|
</span>
|
|
45
45
|
|
|
@@ -48,8 +48,9 @@
|
|
|
48
48
|
</template>
|
|
49
49
|
|
|
50
50
|
<script>
|
|
51
|
-
import { defineComponent, ref
|
|
51
|
+
import { defineComponent, ref } from 'vue';
|
|
52
52
|
import { useFreeField, freeFieldProps } from '../composible/useFreeField';
|
|
53
|
+
import { useFormValidator} from '../../composible/useFormValidator';
|
|
53
54
|
|
|
54
55
|
export default defineComponent({
|
|
55
56
|
name: 'InputFieldYearRange',
|
|
@@ -85,11 +86,9 @@ export default defineComponent({
|
|
|
85
86
|
...freeFieldProps,
|
|
86
87
|
},
|
|
87
88
|
emits:['input'],
|
|
88
|
-
setup(props, { emit }) {
|
|
89
|
+
setup(props, { emit, expose }) {
|
|
89
90
|
if (!props.Field) return () => null;
|
|
90
91
|
|
|
91
|
-
const { proxy:vm } = getCurrentInstance();
|
|
92
|
-
|
|
93
92
|
const { fieldData, setFieldData } = useFreeField(props);
|
|
94
93
|
|
|
95
94
|
const min = ref('');
|
|
@@ -163,6 +162,10 @@ export default defineComponent({
|
|
|
163
162
|
return options;
|
|
164
163
|
});
|
|
165
164
|
|
|
165
|
+
const { validate } = useFormValidator('input_field_validator_first', 'input_field_validator_second');
|
|
166
|
+
expose ({
|
|
167
|
+
validate,
|
|
168
|
+
})
|
|
166
169
|
|
|
167
170
|
return {
|
|
168
171
|
fieldData,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
getCurrentInstance,
|
|
4
4
|
h,
|
|
5
5
|
ref,
|
|
6
|
-
|
|
6
|
+
shallowRef,
|
|
7
7
|
watchEffect,
|
|
8
8
|
computed,
|
|
9
9
|
onMounted,
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
isRef,
|
|
12
12
|
} from "vue";
|
|
13
13
|
import { freeFieldProps } from "./useFreeField";
|
|
14
|
+
import { useFormValidator } from '../../composible/useFormValidator';
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
export default defineComponent({
|
|
16
18
|
name: "FreeFieldWrapper",
|
|
@@ -111,7 +113,7 @@ export default defineComponent({
|
|
|
111
113
|
return props.Field.Hidden;
|
|
112
114
|
});
|
|
113
115
|
|
|
114
|
-
let realComponent =
|
|
116
|
+
let realComponent = shallowRef(null);
|
|
115
117
|
|
|
116
118
|
watchEffect(() => {
|
|
117
119
|
const fComponents = vm.ctx.FieldComponents || {};
|
|
@@ -131,7 +133,7 @@ export default defineComponent({
|
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
realComponent = field;
|
|
136
|
+
realComponent.value = field;
|
|
135
137
|
});
|
|
136
138
|
|
|
137
139
|
if (props.Field && props.Field.Info && props.Field.Info.KeepChanged) {
|
|
@@ -153,20 +155,23 @@ export default defineComponent({
|
|
|
153
155
|
const warningSlot = (!props.noWarning && localField.value.Warning)
|
|
154
156
|
&& h('span', {
|
|
155
157
|
class: 'input-field-warning no-wrap',
|
|
156
|
-
},
|
|
158
|
+
},
|
|
159
|
+
[
|
|
157
160
|
h('span', { class: 'input-field-warning-icon' }),
|
|
158
161
|
h('span', { class: 'input-field-warning-icon-sign-top' }),
|
|
159
162
|
h('span', { class: 'input-field-warning-icon-sign-dot' }),
|
|
160
163
|
h('span', { class: 'input-field-warning-text ellipsis' }, localField.value.Warning),
|
|
161
|
-
]
|
|
164
|
+
]
|
|
165
|
+
);
|
|
162
166
|
|
|
163
|
-
if (realComponent) {
|
|
164
|
-
const compEmits = {};
|
|
165
|
-
(realComponent.emits || []).forEach((em) => {
|
|
166
|
-
if (!em || em === 'input') return;
|
|
167
167
|
|
|
168
|
+
const compEmits = ref({});
|
|
169
|
+
watchEffect(() => {
|
|
170
|
+
(realComponent?.value?.emits || []).forEach((em) => {
|
|
171
|
+
if (!em || em === 'input') return;
|
|
172
|
+
|
|
168
173
|
const captEm = `${em[0].toUpperCase()}${em.substring(1)}`;
|
|
169
|
-
compEmits[`on${captEm}`] = (...args) => {
|
|
174
|
+
compEmits.value[`on${captEm}`] = (...args) => {
|
|
170
175
|
// should not emit event directly as we were not inlucde these events in the emits list
|
|
171
176
|
// but we could get any matched handller from the parent component and then call that
|
|
172
177
|
// handller directly
|
|
@@ -176,46 +181,49 @@ export default defineComponent({
|
|
|
176
181
|
outerHandller(...args);
|
|
177
182
|
}
|
|
178
183
|
};
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
184
|
+
});
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
const readComp = computed(() => realComponent.value && h(
|
|
188
|
+
realComponent.value,
|
|
189
|
+
{
|
|
190
|
+
Field: localField.value,
|
|
191
|
+
values: props.values,
|
|
192
|
+
style: shouldHide.value ? "display:none;" : "",
|
|
193
|
+
class: [
|
|
194
|
+
props.Field.ReadOnly ? "free-field--readonly" : "",
|
|
195
|
+
!shouldHide.value && hasError.value ? "hasError" : "",
|
|
196
|
+
],
|
|
197
|
+
onInput: () => {
|
|
198
|
+
emit("input", props.Field);
|
|
199
|
+
},
|
|
200
|
+
...compEmits,
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
...slots,
|
|
204
|
+
warning: slots.warning ? slots.warning : () => warningSlot,
|
|
205
|
+
}
|
|
206
|
+
));
|
|
207
|
+
|
|
208
|
+
// const emitsRef = computed(() => realComponent?.value?.emits);
|
|
209
|
+
|
|
210
|
+
const {
|
|
211
|
+
validate,
|
|
212
|
+
} = useFormValidator(readComp);
|
|
213
|
+
|
|
214
|
+
expose ({
|
|
215
|
+
// emits: emitsRef.value,
|
|
216
|
+
validate: () => validate.value(props.Field.Name),
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
return realComponent.value ? () => h(
|
|
220
|
+
"div",
|
|
221
|
+
{
|
|
222
|
+
class: wrapperClass,
|
|
223
|
+
},
|
|
224
|
+
[
|
|
225
|
+
readComp.value,
|
|
226
|
+
]
|
|
227
|
+
) : () => null;
|
|
220
228
|
},
|
|
221
229
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h } from 'vue';
|
|
2
|
+
import { QTooltip } from 'quasar';
|
|
2
3
|
|
|
3
4
|
export default defineComponent({
|
|
4
5
|
name: 'FreeFieldLabel',
|
|
@@ -6,13 +7,19 @@ export default defineComponent({
|
|
|
6
7
|
Field: { type: Object },
|
|
7
8
|
},
|
|
8
9
|
setup(props){
|
|
10
|
+
if (!props.Field) return () => null;
|
|
11
|
+
|
|
9
12
|
return () => (props.Field?.Label === void 0) ? null : h('span', {
|
|
10
|
-
class
|
|
11
|
-
|
|
13
|
+
class: {
|
|
14
|
+
'field-label': true,
|
|
15
|
+
'field-label-readonly': props.Field.ReadOnly,
|
|
16
|
+
'field-label-empty': props.Field.Label?.trim().length <= 0,
|
|
17
|
+
required: props.Field.Required,
|
|
18
|
+
},
|
|
12
19
|
}, [
|
|
13
20
|
props.Field.Description && h(QTooltip, {
|
|
14
21
|
anchor: "top right",
|
|
15
|
-
}, props.Field.Description),
|
|
22
|
+
}, () => props.Field.Description),
|
|
16
23
|
props.Field.Label || '',
|
|
17
24
|
props.Field.Required && h('span', {
|
|
18
25
|
class: 'required-mark',
|
package/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { date as quasarDate } from 'quasar';
|
|
2
3
|
import config from '@/config';
|
|
4
|
+
import useAppStore from '@/stores/app';
|
|
3
5
|
import MsgDialog from './components/Dialog/index';
|
|
4
6
|
|
|
5
7
|
import EIcon from './components/Basic/EIcon.vue';
|
|
@@ -20,12 +22,29 @@ import routers from './router';
|
|
|
20
22
|
|
|
21
23
|
// global filters
|
|
22
24
|
const filters = {
|
|
23
|
-
serverImage: url =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
serverImage: (url) => {
|
|
26
|
+
if (typeof url === 'string' && url.startsWith('@')) return url.substring(1);
|
|
27
|
+
|
|
28
|
+
return url ? `${config.imageUrlBase}${url}` : '';
|
|
29
|
+
},
|
|
30
|
+
serverVideo: (url) => {
|
|
31
|
+
if (typeof url === 'string' && url.startsWith('@')) return url.substring(1);
|
|
32
|
+
|
|
33
|
+
return url ? `${config.videoUrlBase}${url}` : '';
|
|
34
|
+
},
|
|
35
|
+
serverThumb: (url) => {
|
|
36
|
+
if (typeof url === 'string' && url.startsWith('@')) return url.substring(1);
|
|
37
|
+
|
|
38
|
+
return url ? `${config.thumbUrlBase}${url}` : '';
|
|
39
|
+
},
|
|
40
|
+
serverDocument: (url) => {
|
|
41
|
+
if (typeof url === 'string' && url.startsWith('@')) return url.substring(1);
|
|
42
|
+
|
|
43
|
+
return url ? `${config.documentUrlBase}${url}` : '';
|
|
44
|
+
},
|
|
27
45
|
serverPath: (url) => {
|
|
28
46
|
if (!url) return '';
|
|
47
|
+
if (typeof url === 'string' && url.startsWith('@')) return url.substring(1);
|
|
29
48
|
|
|
30
49
|
const dotIndex = url.lastIndexOf('.');
|
|
31
50
|
const ext = url.substring(dotIndex, url.length).toLowerCase();
|
|
@@ -100,117 +119,143 @@ const filters = {
|
|
|
100
119
|
return filters.padding((date.getDate()));
|
|
101
120
|
},
|
|
102
121
|
ago: (d) => {
|
|
103
|
-
|
|
104
|
-
|
|
122
|
+
const date1 = new Date();
|
|
123
|
+
const date2 = new Date(d);
|
|
105
124
|
|
|
106
|
-
let diff =
|
|
125
|
+
let diff = quasarDate.getDateDiff(date1, date2, 'seconds');
|
|
107
126
|
if (diff < 1) {
|
|
108
|
-
return diff +
|
|
109
|
-
}
|
|
110
|
-
return diff +
|
|
127
|
+
return diff + Vue.prototype.$t('justNow');
|
|
128
|
+
} if (diff < 60) {
|
|
129
|
+
return diff + Vue.prototype.$t('secondsAgo');
|
|
111
130
|
}
|
|
112
131
|
|
|
113
|
-
diff =
|
|
132
|
+
diff = quasarDate.getDateDiff(date1, date2, 'minutes');
|
|
114
133
|
if (diff < 60) {
|
|
115
|
-
return diff +
|
|
134
|
+
return diff + Vue.prototype.$t('minutesAgo');
|
|
116
135
|
}
|
|
117
136
|
|
|
118
137
|
if (diff < 24) {
|
|
119
|
-
return diff +
|
|
138
|
+
return diff + Vue.prototype.$t('hoursAgo');
|
|
120
139
|
}
|
|
121
140
|
|
|
122
|
-
diff =
|
|
141
|
+
diff = quasarDate.getDateDiff(date1, date2, 'days');
|
|
123
142
|
if (diff < 31) {
|
|
124
|
-
return diff +
|
|
143
|
+
return diff + Vue.prototype.$t('daysAgo');
|
|
125
144
|
}
|
|
126
145
|
|
|
127
|
-
diff =
|
|
146
|
+
diff = quasarDate.getDateDiff(date1, date2, 'months');
|
|
128
147
|
if (diff < 13) {
|
|
129
|
-
return diff +
|
|
148
|
+
return diff + Vue.prototype.$t('monthsAgo');
|
|
130
149
|
}
|
|
131
150
|
|
|
132
|
-
diff =
|
|
133
|
-
return diff +
|
|
151
|
+
diff = quasarDate.getDateDiff(date1, date2, 'years');
|
|
152
|
+
return diff + Vue.prototype.$t('yearsAgo');
|
|
134
153
|
},
|
|
135
154
|
};
|
|
136
155
|
|
|
137
156
|
export default (app, root) => {
|
|
138
157
|
root.use(MsgDialog);
|
|
139
158
|
|
|
159
|
+
const appStore = useAppStore();
|
|
160
|
+
|
|
140
161
|
return {
|
|
141
162
|
config: {
|
|
142
163
|
backendDependencies: ["core-modules"],
|
|
143
164
|
dictFields: [
|
|
144
165
|
{
|
|
145
|
-
Type:
|
|
146
|
-
Label:
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
Name: "Index",
|
|
150
|
-
Label: "排序号",
|
|
151
|
-
Type: "Number",
|
|
166
|
+
Type: 'Category',
|
|
167
|
+
Label: '字典数据信息',
|
|
152
168
|
},
|
|
153
169
|
{
|
|
154
|
-
Name:
|
|
155
|
-
Label:
|
|
156
|
-
Type:
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
Name: "Label",
|
|
160
|
-
Label: "显示名称",
|
|
161
|
-
Type: "String",
|
|
170
|
+
Name: 'Index',
|
|
171
|
+
Label: '排序号',
|
|
172
|
+
Type: 'Number',
|
|
162
173
|
},
|
|
163
174
|
{
|
|
164
|
-
Name:
|
|
165
|
-
Label:
|
|
166
|
-
Type:
|
|
175
|
+
Name: 'Name',
|
|
176
|
+
Label: '数据名称',
|
|
177
|
+
Type: 'String',
|
|
167
178
|
},
|
|
179
|
+
// {
|
|
180
|
+
// Name: 'Label',
|
|
181
|
+
// Label: '显示名称',
|
|
182
|
+
// Type: 'String',
|
|
183
|
+
// },
|
|
184
|
+
// {
|
|
185
|
+
// Name: 'Description',
|
|
186
|
+
// Label: '说明',
|
|
187
|
+
// Type: 'Text',
|
|
188
|
+
// },
|
|
168
189
|
{
|
|
169
|
-
Name:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
Label: "普通类型",
|
|
175
|
-
Value: "String",
|
|
176
|
-
},
|
|
190
|
+
Name: 'Labels',
|
|
191
|
+
Type: 'Tabs',
|
|
192
|
+
Label: '显示内容',
|
|
193
|
+
DataType: 'Array',
|
|
194
|
+
Default: [
|
|
177
195
|
{
|
|
178
|
-
|
|
179
|
-
Value: "File",
|
|
196
|
+
Locale: appStore.locale || app.config.defaultLocale,
|
|
180
197
|
},
|
|
181
198
|
],
|
|
199
|
+
Options: {
|
|
200
|
+
Dense: true,
|
|
201
|
+
LabelField: 'Name',
|
|
202
|
+
ValueField: 'Locale',
|
|
203
|
+
List: [
|
|
204
|
+
{
|
|
205
|
+
Name: 'Locale',
|
|
206
|
+
Label: '语言',
|
|
207
|
+
Type: 'String',
|
|
208
|
+
ReadOnly: true,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
Name: 'Label',
|
|
212
|
+
Label: '显示名称',
|
|
213
|
+
Type: 'String',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
Name: 'Description',
|
|
217
|
+
Label: '说明',
|
|
218
|
+
Type: 'Text',
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
},
|
|
182
222
|
},
|
|
183
223
|
{
|
|
184
|
-
Name:
|
|
185
|
-
Label:
|
|
186
|
-
Type:
|
|
224
|
+
Name: 'Type',
|
|
225
|
+
Label: '类型',
|
|
226
|
+
Type: 'Select',
|
|
227
|
+
Options: [{
|
|
228
|
+
Label: '普通类型',
|
|
229
|
+
Value: 'String',
|
|
230
|
+
}, {
|
|
231
|
+
Label: '文件',
|
|
232
|
+
Value: 'File',
|
|
233
|
+
}],
|
|
187
234
|
},
|
|
188
235
|
{
|
|
189
|
-
Name:
|
|
190
|
-
Label:
|
|
191
|
-
Type:
|
|
192
|
-
MaxValue: "100m",
|
|
193
|
-
Options: {
|
|
194
|
-
Dense: false,
|
|
195
|
-
AsLink: false,
|
|
196
|
-
Ext: "jpg,png,pdf,doc,docx,zip",
|
|
197
|
-
},
|
|
198
|
-
Tips: [
|
|
199
|
-
{
|
|
200
|
-
Text: "文件不可超过100M。格式支持:PNG、JPG、PDF、DOC、DOCX、ZIP。",
|
|
201
|
-
},
|
|
202
|
-
],
|
|
236
|
+
Name: 'Value',
|
|
237
|
+
Label: '值',
|
|
238
|
+
Type: 'String',
|
|
203
239
|
},
|
|
204
240
|
{
|
|
205
|
-
|
|
206
|
-
Label:
|
|
241
|
+
Name: 'Image',
|
|
242
|
+
Label: '图片/图标/文件',
|
|
243
|
+
Type: 'File',
|
|
244
|
+
MaxValue: '100m',
|
|
245
|
+
Options: { Dense: false, AsLink: false, Ext: 'jpg,png,pdf,doc,docx,zip' },
|
|
246
|
+
Tips: [{
|
|
247
|
+
Text: '文件不可超过100M。格式支持:PNG、JPG、PDF、DOC、DOCX、ZIP。',
|
|
248
|
+
}],
|
|
207
249
|
},
|
|
208
250
|
{
|
|
209
|
-
|
|
210
|
-
Label:
|
|
211
|
-
Type: "Text",
|
|
251
|
+
Type: 'Category',
|
|
252
|
+
Label: '高级设置',
|
|
212
253
|
},
|
|
213
|
-
|
|
254
|
+
{
|
|
255
|
+
Name: 'Info',
|
|
256
|
+
Label: '附加信息',
|
|
257
|
+
Type: 'Text',
|
|
258
|
+
}],
|
|
214
259
|
menuFields: [
|
|
215
260
|
{
|
|
216
261
|
Type: "Category",
|
|
@@ -275,29 +320,29 @@ export default (app, root) => {
|
|
|
275
320
|
LeveledMenus,
|
|
276
321
|
BreadCrumbs,
|
|
277
322
|
ThemeSwitch,
|
|
278
|
-
...FieldComponents.components,
|
|
279
323
|
Mourning,
|
|
324
|
+
...FieldComponents.components,
|
|
280
325
|
},
|
|
281
326
|
fieldComponents: FieldComponents.fieldComponents,
|
|
282
327
|
|
|
283
328
|
validators: {
|
|
284
329
|
validatorNotEmpty: (d) =>
|
|
285
|
-
d
|
|
330
|
+
d && d.length > 0 && d.trim().length > 0,
|
|
286
331
|
validatorMobilePhone: (d) =>
|
|
287
|
-
/^(0|86|17951)?(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])[0-9]{8}$/.test(
|
|
332
|
+
!d || /^(0|86|17951)?(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])[0-9]{8}$/.test(
|
|
288
333
|
d
|
|
289
334
|
),
|
|
290
335
|
validatorEmail: (d) =>
|
|
291
|
-
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
|
336
|
+
!d || /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
|
292
337
|
d
|
|
293
338
|
),
|
|
294
339
|
validatorPhoneOrEmail: (d) =>
|
|
295
|
-
d !==
|
|
340
|
+
d !== void 0 &&
|
|
296
341
|
d.length > 0 &&
|
|
297
|
-
(this.
|
|
342
|
+
(this.validatorMobilePhone(d) || this.validatorEmail(d)),
|
|
298
343
|
// validatorMinLength: (d, len = 0) => d !== undefined && d.length >= len,
|
|
299
344
|
validatorChinaIDNumber: (d) =>
|
|
300
|
-
/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(
|
|
345
|
+
!d || /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(
|
|
301
346
|
d
|
|
302
347
|
),
|
|
303
348
|
// validatorSame: (d, to) => d === to,
|
package/package.json
CHANGED
package/view/dict/index.vue
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
style="border-bottom: solid 1px grey;"
|
|
17
17
|
>
|
|
18
18
|
<div>
|
|
19
|
-
{{ prop.node
|
|
19
|
+
{{ dictLabel(prop.node) }}
|
|
20
20
|
<span
|
|
21
21
|
v-if="prop.node.level === 1 && prop.node.Name"
|
|
22
22
|
class="dictionary-data-name"
|
|
@@ -78,11 +78,29 @@
|
|
|
78
78
|
</div>
|
|
79
79
|
</template>
|
|
80
80
|
</q-tree>
|
|
81
|
+
|
|
82
|
+
<div class="row items-center justify-center q-my-md" v-if="canImport">
|
|
83
|
+
<q-btn flat @click="exportTranslates" class="btn-primary q-mr-md">导出翻译</q-btn>
|
|
84
|
+
<q-btn flat @click="importTranslates" class="btn-primary">导入翻译</q-btn>
|
|
85
|
+
|
|
86
|
+
<div class="row full-width q-mt-md">
|
|
87
|
+
<q-input v-if="showImportTextArea"
|
|
88
|
+
class="full-width"
|
|
89
|
+
type="textarea"
|
|
90
|
+
autogrow
|
|
91
|
+
v-model="importText"
|
|
92
|
+
placeholder="请输入要导入的内容(tab键分割),如:
|
|
93
|
+
xxx类型 类型一 en-us Type One
|
|
94
|
+
xxx类型 类型二 en-us Type Two"></q-input>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
81
97
|
</div>
|
|
82
98
|
</template>
|
|
83
99
|
|
|
84
100
|
<script>
|
|
85
101
|
import { defineComponent } from 'vue';
|
|
102
|
+
import { copyToClipboard } from 'quasar';
|
|
103
|
+
import { requests } from '@/boot/axios';
|
|
86
104
|
import { useObjectData, objectDataProps } from '../../composible/useObjectData';
|
|
87
105
|
|
|
88
106
|
export default defineComponent({
|
|
@@ -98,6 +116,9 @@ export default defineComponent({
|
|
|
98
116
|
selectedDictNode: {},
|
|
99
117
|
editingDict: {},
|
|
100
118
|
dictFields: [],
|
|
119
|
+
canImport: false,
|
|
120
|
+
importText: '',
|
|
121
|
+
showImportTextArea: false,
|
|
101
122
|
};
|
|
102
123
|
},
|
|
103
124
|
setup(props, ctx) {
|
|
@@ -124,9 +145,26 @@ export default defineComponent({
|
|
|
124
145
|
}
|
|
125
146
|
},
|
|
126
147
|
},
|
|
148
|
+
beforeCreate() {
|
|
149
|
+
requests.canI('dict/import').then((r) => {
|
|
150
|
+
if (r) {
|
|
151
|
+
this.canImport = true;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
},
|
|
127
155
|
created() {
|
|
128
156
|
this.dictFields = this.getModule('core-modules').config.dictFields;
|
|
129
157
|
},
|
|
158
|
+
computed: {
|
|
159
|
+
dictLabel() {
|
|
160
|
+
return (d) => {
|
|
161
|
+
if (!d || !d.Labels) return '';
|
|
162
|
+
|
|
163
|
+
const lb = d.Labels.find((l) => l.Locale === this.$i18n.locale );
|
|
164
|
+
return lb && lb.Label;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
},
|
|
130
168
|
methods: {
|
|
131
169
|
loadSubDicts({ key, done, node /* , fail */ }) {
|
|
132
170
|
this.GetData(key, node.level)
|
|
@@ -153,6 +191,27 @@ export default defineComponent({
|
|
|
153
191
|
}
|
|
154
192
|
},
|
|
155
193
|
editNode(n) {
|
|
194
|
+
if (!n) return;
|
|
195
|
+
|
|
196
|
+
n.Labels = n.Labels || [];
|
|
197
|
+
// check labels according to the locales
|
|
198
|
+
const locales = this.ctx.config.locales || [];
|
|
199
|
+
for(let i = 0; i < locales.length; i += 1) {
|
|
200
|
+
const locale = locales[i];
|
|
201
|
+
const existsLabel = n.Labels.find((l) => l.Locale === locale.locale);
|
|
202
|
+
|
|
203
|
+
if (!existsLabel) {
|
|
204
|
+
n.Labels.push({
|
|
205
|
+
Label: '',
|
|
206
|
+
Locale: locale.locale,
|
|
207
|
+
Description: '',
|
|
208
|
+
Name: locale.name,
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
existsLabel.Name = locale.name;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
156
215
|
if (this.selectedDictNode && this.selectedDictNode.id === n.id) {
|
|
157
216
|
this.selectedDictNode = {};
|
|
158
217
|
this.editingDict = {};
|
|
@@ -276,6 +335,31 @@ export default defineComponent({
|
|
|
276
335
|
this.onCancelClick();
|
|
277
336
|
}
|
|
278
337
|
},
|
|
338
|
+
importTranslates() {
|
|
339
|
+
if (!this.showImportTextArea) {
|
|
340
|
+
this.showImportTextArea = true;
|
|
341
|
+
this.importText = '';
|
|
342
|
+
} else {
|
|
343
|
+
// do the i
|
|
344
|
+
this.postRequest('/dict/import/trans', {c: this.importText}).then((d) => {
|
|
345
|
+
const data = d && d.data;
|
|
346
|
+
if (d && d.msg === 'OK') {
|
|
347
|
+
this.$q.notify('导入成功!');
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
exportTranslates() {
|
|
353
|
+
this.showImportTextArea = false;
|
|
354
|
+
this.getRequest('/dict/export/trans').then((d) => {
|
|
355
|
+
const data = (d && d.data) || {};
|
|
356
|
+
|
|
357
|
+
if (d.data.c) {
|
|
358
|
+
copyToClipboard(d.data.c);
|
|
359
|
+
this.$q.notify('已拷贝到剪切板,可直接粘贴至excel等工具!');
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
},
|
|
279
363
|
},
|
|
280
364
|
});
|
|
281
365
|
</script>
|