free-fe-core-modules 0.0.5 → 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 +4 -2
- package/components/FloatingWindow/index.vue +9 -1
- package/components/SlidingCarousel/index.vue +5 -2
- package/components/SlidingNews/index.vue +33 -24
- package/free-field/Fields/Category.js +2 -1
- package/free-field/Fields/Check.js +1 -0
- package/free-field/Fields/DynamicList.js +14 -11
- package/free-field/Fields/TimeRange.vue +4 -2
- 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/mourning/mourning.vue +17 -12
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
/>
|
|
10
10
|
<q-space></q-space>
|
|
11
11
|
<q-btn v-if="meta.length > 0 && canBack"
|
|
12
|
-
flat icon="keyboard_arrow_left" @click="back">{{backText}}</q-btn>
|
|
12
|
+
flat icon="keyboard_arrow_left" @click="back">{{$t(backText)}}</q-btn>
|
|
13
13
|
</q-breadcrumbs>
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script>
|
|
17
17
|
import { defineComponent } from 'vue';
|
|
18
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
18
19
|
import { mapWritableState } from 'pinia';
|
|
19
20
|
import useAppStore from '@/stores/app';
|
|
20
21
|
|
|
@@ -24,6 +25,14 @@ export default defineComponent({
|
|
|
24
25
|
canBack: { type: Boolean, default: true },
|
|
25
26
|
backText: { type: String, default: '返回' },
|
|
26
27
|
},
|
|
28
|
+
setup() {
|
|
29
|
+
const router = useRouter();
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
router,
|
|
33
|
+
route: useRoute(),
|
|
34
|
+
};
|
|
35
|
+
},
|
|
27
36
|
data() {
|
|
28
37
|
return {
|
|
29
38
|
nextFlag: false,
|
|
@@ -37,11 +46,11 @@ export default defineComponent({
|
|
|
37
46
|
let mt = [];
|
|
38
47
|
if (this.crumbs && this.crumbs.length) {
|
|
39
48
|
mt = this.crumbs;
|
|
40
|
-
} else if (this
|
|
41
|
-
mt = this
|
|
49
|
+
} else if (this.route.meta && this.route.meta.length) {
|
|
50
|
+
mt = this.route.meta;
|
|
42
51
|
} else {
|
|
43
|
-
for (let i = 0; i < this
|
|
44
|
-
const rm = this
|
|
52
|
+
for (let i = 0; i < this.route.matched.length; i += 1) {
|
|
53
|
+
const rm = this.route.matched[i];
|
|
45
54
|
if (rm.meta && rm.meta.length) mt = rm.meta;
|
|
46
55
|
}
|
|
47
56
|
}
|
|
@@ -65,14 +74,14 @@ export default defineComponent({
|
|
|
65
74
|
return;
|
|
66
75
|
}
|
|
67
76
|
|
|
68
|
-
this
|
|
77
|
+
this.router.push(this.meta[index].route);
|
|
69
78
|
// const backIndex = this.meta.length - 1 - index;
|
|
70
79
|
// window.history.go(-backIndex);
|
|
71
80
|
},
|
|
72
81
|
back() {
|
|
73
|
-
const URL = this
|
|
74
|
-
? this
|
|
75
|
-
: this
|
|
82
|
+
const URL = this.route.fullPath.indexOf('?') === -1
|
|
83
|
+
? this.route.fullPath
|
|
84
|
+
: this.route.fullPath.split('?')[0];
|
|
76
85
|
if (this.whiteList.indexOf(URL) === -1) {
|
|
77
86
|
window.history.go(-1);
|
|
78
87
|
} else {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
v-if="!m.Sub || m.Sub.length <= 0"
|
|
7
7
|
clickable
|
|
8
8
|
class="simple"
|
|
9
|
-
:class="group"
|
|
9
|
+
:class="`${group} level_${level || 0}`"
|
|
10
10
|
:to="m.Route"
|
|
11
11
|
expand-icon-class="simple-expand-icon"
|
|
12
12
|
:ref="`menuItem_${group}_index`"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<q-icon class="leaf-icon" :name="m.Icon"></q-icon>
|
|
18
18
|
</q-item-section>
|
|
19
19
|
<q-item-section>
|
|
20
|
-
<div class="q-item__label leaf-label">{{$t(m.Label)}}</div>
|
|
20
|
+
<div class="q-item__label leaf-label">{{translate ? $t(m.Label) : m.Label}}</div>
|
|
21
21
|
</q-item-section>
|
|
22
22
|
<q-item-section side
|
|
23
23
|
class="leaf-expand-icon">
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
|
|
33
33
|
<q-expansion-item
|
|
34
34
|
v-if="m.Sub && m.Sub.length > 0"
|
|
35
|
-
:
|
|
35
|
+
:modelValue="m.Sub.filter(s => $route.fullPath.startsWith(s.Route)).length > 0"
|
|
36
36
|
exact
|
|
37
37
|
class="expansion"
|
|
38
|
-
:class="group"
|
|
38
|
+
:class="`${group} level_${level || 0}`"
|
|
39
39
|
:dense-toggle="dense"
|
|
40
40
|
expand-icon-class="expansion-icon"
|
|
41
41
|
:expand-icon="expandIcon"
|
|
@@ -44,13 +44,14 @@
|
|
|
44
44
|
:content-inset-level="inset ? insetLevel || (showIcon ? 0.6 : 0.4) : undefined"
|
|
45
45
|
expand-separator
|
|
46
46
|
:icon="(showIcon && m.Icon) ? m.Icon : undefined"
|
|
47
|
-
:label="$t(m.Label)"
|
|
47
|
+
:label="translate ? $t(m.Label) : m.Label"
|
|
48
48
|
:to="m.Route"
|
|
49
49
|
:ref="`menuItem_${group}_index`"
|
|
50
50
|
>
|
|
51
51
|
<leveled-menus
|
|
52
52
|
:menus="m.Sub"
|
|
53
53
|
:group="`${group}_${index}`"
|
|
54
|
+
:level="level + 1"
|
|
54
55
|
:showIcon="showIcon"
|
|
55
56
|
:insetLevel="insetLevel"
|
|
56
57
|
:dense="dense"
|
|
@@ -71,6 +72,7 @@ import { defineComponent } from 'vue';
|
|
|
71
72
|
export default defineComponent({
|
|
72
73
|
name: 'LeveledMenus',
|
|
73
74
|
props: {
|
|
75
|
+
level: { type: Number, default: 0 },
|
|
74
76
|
group: { type: String, default: 'DEFAULT' },
|
|
75
77
|
menus: { type: Array },
|
|
76
78
|
showIcon: { type: Boolean, default: true },
|
|
@@ -81,7 +83,13 @@ export default defineComponent({
|
|
|
81
83
|
leafExpandedIcon: { type: String, default: undefined },
|
|
82
84
|
expandIcon: { type: String, default: undefined },
|
|
83
85
|
expandedIcon: { type: String, default: undefined },
|
|
86
|
+
translate: { type: Boolean, default: false },
|
|
84
87
|
},
|
|
85
88
|
});
|
|
86
89
|
</script>
|
|
87
90
|
|
|
91
|
+
<style lang="sass">
|
|
92
|
+
.leveled-menu
|
|
93
|
+
.simple-expand-icon
|
|
94
|
+
display: none
|
|
95
|
+
</style>
|
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
|
|
77
77
|
<script>
|
|
78
78
|
import { defineComponent } from 'vue';
|
|
79
|
+
import { useRouter } from 'vue-router'
|
|
79
80
|
import { useObjectData, objectDataProps } from '../../composible/useObjectData';
|
|
80
81
|
|
|
81
82
|
export default defineComponent({
|
|
@@ -90,10 +91,12 @@ export default defineComponent({
|
|
|
90
91
|
data,
|
|
91
92
|
refreshData,
|
|
92
93
|
} = useObjectData(props, ctx);
|
|
94
|
+
const router = useRouter();
|
|
93
95
|
|
|
94
96
|
return {
|
|
95
|
-
data,
|
|
97
|
+
data,
|
|
96
98
|
refreshData,
|
|
99
|
+
router,
|
|
97
100
|
};
|
|
98
101
|
},
|
|
99
102
|
created() {
|
|
@@ -150,7 +153,7 @@ export default defineComponent({
|
|
|
150
153
|
// if (item.route_query) rParams.query = item.route_query;
|
|
151
154
|
// if (item.route_params) rParams.params = item.route_params;
|
|
152
155
|
|
|
153
|
-
this
|
|
156
|
+
this.router.push(item.route);
|
|
154
157
|
}
|
|
155
158
|
});
|
|
156
159
|
},
|
|
@@ -66,6 +66,8 @@
|
|
|
66
66
|
:Field="field"
|
|
67
67
|
:values="fieldsData"
|
|
68
68
|
ref="fieldsToValid"
|
|
69
|
+
@cancel="btnCancel"
|
|
70
|
+
@ok="onOKClick"
|
|
69
71
|
@input="onInputFieldInput(field)"
|
|
70
72
|
></free-field>
|
|
71
73
|
</div>
|
|
@@ -75,7 +77,7 @@
|
|
|
75
77
|
<q-card-actions
|
|
76
78
|
align="center"
|
|
77
79
|
class="action-buttons full-width absolute"
|
|
78
|
-
v-if="canOK || canCancel"
|
|
80
|
+
v-if="(canOK || canCancel) && !hideActions"
|
|
79
81
|
>
|
|
80
82
|
<q-btn
|
|
81
83
|
:label="cancelText"
|
|
@@ -126,6 +128,7 @@ export default defineComponent({
|
|
|
126
128
|
needText: { type: Boolean, default: false },
|
|
127
129
|
text_label: { type: String, default: '' },
|
|
128
130
|
max_text_length: { type: Number, default: 100 },
|
|
131
|
+
hideActions: { type: Boolean, default: false },
|
|
129
132
|
canOK: { type: Boolean, default: true },
|
|
130
133
|
canCancel: { type: Boolean, default: false },
|
|
131
134
|
canClose: { type: Boolean, default: false },
|
|
@@ -205,7 +208,6 @@ export default defineComponent({
|
|
|
205
208
|
// following method is REQUIRED
|
|
206
209
|
// (don't change its name --> "show")
|
|
207
210
|
show() {
|
|
208
|
-
// debugger
|
|
209
211
|
this.$refs.dialog.show();
|
|
210
212
|
this.timeout_counter();
|
|
211
213
|
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
<script>
|
|
17
17
|
import { defineComponent } from 'vue';
|
|
18
|
+
import { useRouter } from 'vue-router'
|
|
18
19
|
|
|
19
20
|
export default defineComponent({
|
|
20
21
|
name: 'FloatingWindow',
|
|
@@ -24,6 +25,13 @@ export default defineComponent({
|
|
|
24
25
|
onlyIn: { type: Array, default: () => [] },
|
|
25
26
|
top: { type: Number, default: 0 },
|
|
26
27
|
},
|
|
28
|
+
setup() {
|
|
29
|
+
const router = useRouter();
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
router,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
27
35
|
data() {
|
|
28
36
|
return {
|
|
29
37
|
x: 150,
|
|
@@ -53,7 +61,7 @@ export default defineComponent({
|
|
|
53
61
|
if (/^(http|https):\/\/.*/.test(this.url)) {
|
|
54
62
|
window.open(this.url);
|
|
55
63
|
} else {
|
|
56
|
-
this
|
|
64
|
+
this.router.push(this.url);
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
},
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
<script>
|
|
29
29
|
import { defineComponent } from 'vue';
|
|
30
|
+
import { useRouter } from 'vue-router'
|
|
30
31
|
import { useObjectData, objectDataProps } from '../../composible/useObjectData';
|
|
31
32
|
|
|
32
33
|
export default defineComponent({
|
|
@@ -48,9 +49,11 @@ export default defineComponent({
|
|
|
48
49
|
refreshData,
|
|
49
50
|
} = useObjectData(props, ctx);
|
|
50
51
|
|
|
52
|
+
const router = useRouter();
|
|
51
53
|
return {
|
|
52
|
-
data,
|
|
54
|
+
data,
|
|
53
55
|
refreshData,
|
|
56
|
+
router,
|
|
54
57
|
};
|
|
55
58
|
},
|
|
56
59
|
data() {
|
|
@@ -77,7 +80,7 @@ export default defineComponent({
|
|
|
77
80
|
// window.location.href = l;
|
|
78
81
|
window.open(carouse.url);
|
|
79
82
|
} else {
|
|
80
|
-
this
|
|
83
|
+
this.router.push(carouse.url);
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div
|
|
3
3
|
v-if="visible"
|
|
4
4
|
class="row full-width sliding-news justify-center"
|
|
5
|
-
:class="(
|
|
5
|
+
:class="(localData.length) ? '' : 'empty'"
|
|
6
6
|
>
|
|
7
7
|
<span class="sliding-news-label row items-center">
|
|
8
8
|
<e-icon
|
|
@@ -26,23 +26,19 @@
|
|
|
26
26
|
vertical
|
|
27
27
|
>
|
|
28
28
|
<q-carousel-slide
|
|
29
|
-
v-for="(carouse, index) in
|
|
29
|
+
v-for="(carouse, index) in localData"
|
|
30
30
|
:key="index"
|
|
31
31
|
:name="index"
|
|
32
32
|
@click="newsClicked(carouse)"
|
|
33
33
|
style="cursor: pointer; padding: 0; margin: 0;"
|
|
34
34
|
>
|
|
35
|
-
<div class="row items-center justify-center full-height">
|
|
36
|
-
<
|
|
35
|
+
<div class="row no-wrap items-center justify-center full-height">
|
|
36
|
+
<div class="sliding-news-title col ellipsis">{{carouse.title}}</div>
|
|
37
37
|
<q-space />
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
class="sliding-news-date"
|
|
41
|
-
:style="`line-height: ${heightString}`"
|
|
42
|
-
>
|
|
38
|
+
<div class="sliding-news-right"
|
|
39
|
+
:style="`line-height: ${heightString}`">
|
|
43
40
|
{{filter('normalDate',(carouse.PublishDate || carouse.LastUpdateDate))}}
|
|
44
|
-
|
|
45
|
-
</span>
|
|
41
|
+
</div>
|
|
46
42
|
</div>
|
|
47
43
|
</q-carousel-slide>
|
|
48
44
|
</q-carousel>
|
|
@@ -65,6 +61,7 @@
|
|
|
65
61
|
</template>
|
|
66
62
|
|
|
67
63
|
<script>
|
|
64
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
68
65
|
import { defineComponent } from 'vue';
|
|
69
66
|
import { useObjectData, objectDataProps } from '../../composible/useObjectData';
|
|
70
67
|
|
|
@@ -72,6 +69,13 @@ export default defineComponent({
|
|
|
72
69
|
name: 'SlidingNews',
|
|
73
70
|
props: {
|
|
74
71
|
...objectDataProps,
|
|
72
|
+
fields: {
|
|
73
|
+
type: Object,
|
|
74
|
+
default: () => ({
|
|
75
|
+
title: 'Title',
|
|
76
|
+
date: 'LastUpdateDate'
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
75
79
|
interval: { type: Number, default: 3000 },
|
|
76
80
|
height: { type: String, default: '40px' },
|
|
77
81
|
width: { type: String, default: '100%' },
|
|
@@ -88,10 +92,13 @@ export default defineComponent({
|
|
|
88
92
|
data,
|
|
89
93
|
refreshData,
|
|
90
94
|
} = useObjectData(props, ctx);
|
|
95
|
+
const router = useRouter();
|
|
91
96
|
|
|
92
97
|
return {
|
|
93
|
-
data,
|
|
98
|
+
data,
|
|
94
99
|
refreshData,
|
|
100
|
+
router,
|
|
101
|
+
route: useRoute(),
|
|
95
102
|
};
|
|
96
103
|
},
|
|
97
104
|
data() {
|
|
@@ -113,24 +120,26 @@ export default defineComponent({
|
|
|
113
120
|
return this.height;
|
|
114
121
|
},
|
|
115
122
|
},
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
localData() {
|
|
124
|
+
const fks = Object.keys(this.fields || {});
|
|
125
|
+
return (this.data || []).map((dd) => {
|
|
126
|
+
const ret = {};
|
|
127
|
+
for (let i = 0; i < fks.length; i += 1) {
|
|
128
|
+
const fk = fks[i];
|
|
129
|
+
ret[fk] = dd[this.fields[fk]];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { ...dd, ...ret };
|
|
133
|
+
});
|
|
134
|
+
},
|
|
126
135
|
methods: {
|
|
127
136
|
newsClicked(news) {
|
|
128
137
|
let url = '';
|
|
129
138
|
if (news.url) url += news.url;
|
|
130
139
|
else if (this.url) url += `${this.url}${news.id || ''}`;
|
|
131
140
|
|
|
132
|
-
if (url && this
|
|
133
|
-
this
|
|
141
|
+
if (url && this.route.fullPath !== url) {
|
|
142
|
+
this.router.push({ path: url });
|
|
134
143
|
}
|
|
135
144
|
},
|
|
136
145
|
// carouselNext() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h } from 'vue';
|
|
2
|
+
import { freeFieldProps } from '../composible/useFreeField';
|
|
2
3
|
|
|
3
4
|
export default defineComponent({
|
|
4
5
|
name: 'InputFieldCategory',
|
|
@@ -9,7 +10,7 @@ export default defineComponent({
|
|
|
9
10
|
Description: '',
|
|
10
11
|
},
|
|
11
12
|
props: {
|
|
12
|
-
|
|
13
|
+
...freeFieldProps,
|
|
13
14
|
},
|
|
14
15
|
methods: {
|
|
15
16
|
},
|
|
@@ -76,6 +76,7 @@ export default defineComponent({
|
|
|
76
76
|
if (!props.Field) return {};
|
|
77
77
|
|
|
78
78
|
const { fieldData, setFieldData } = useFreeField(props);
|
|
79
|
+
fieldData.value = fieldData.value || false;
|
|
79
80
|
|
|
80
81
|
const before = (props.Field.showLabel && !props.Field.dense && props.Field.Label !== void 0) ? () => h(freeFieldLabel, {
|
|
81
82
|
Field: props.Field,
|
|
@@ -463,7 +463,8 @@ export default defineComponent({
|
|
|
463
463
|
);
|
|
464
464
|
|
|
465
465
|
const bodyCell = (slotProps) => {
|
|
466
|
-
|
|
466
|
+
const fields = ref([]);
|
|
467
|
+
fields.value = slotProps.col?.List?.length > 1 ? slotProps.col.List.map((col) =>
|
|
467
468
|
h(FreeField, {
|
|
468
469
|
Field: columnField(col, true, slotProps.col),
|
|
469
470
|
values: slotProps.row,
|
|
@@ -478,7 +479,11 @@ export default defineComponent({
|
|
|
478
479
|
onInput: cellChanged,
|
|
479
480
|
}),
|
|
480
481
|
];
|
|
481
|
-
|
|
482
|
+
|
|
483
|
+
// add fields from the current cell to validate list
|
|
484
|
+
fieldsToValidate.value.push(...fields.value);
|
|
485
|
+
|
|
486
|
+
|
|
482
487
|
if (slotProps.col.name === "listActions") {
|
|
483
488
|
return h(QTd, null, {
|
|
484
489
|
default: () =>
|
|
@@ -503,15 +508,13 @@ export default defineComponent({
|
|
|
503
508
|
rowspan: slotProps.value ? slotProps.value.rowspan || "1" : "1",
|
|
504
509
|
class: "items-center justify-center",
|
|
505
510
|
},
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
)
|
|
514
|
-
]
|
|
511
|
+
() => h(
|
|
512
|
+
"span",
|
|
513
|
+
{
|
|
514
|
+
class: "full-height full-width",
|
|
515
|
+
},
|
|
516
|
+
fields.value,
|
|
517
|
+
)
|
|
515
518
|
);
|
|
516
519
|
}
|
|
517
520
|
};
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
</template>
|
|
97
97
|
|
|
98
98
|
<script>
|
|
99
|
-
import { defineComponent, ref, getCurrentInstance } from 'vue';
|
|
99
|
+
import { defineComponent, ref, getCurrentInstance, watch, watchEffect, computed } from 'vue';
|
|
100
100
|
import { useFreeField, freeFieldProps } from '../composible/useFreeField';
|
|
101
101
|
import { useFormValidator} from '../../composible/useFormValidator';
|
|
102
102
|
|
|
@@ -300,7 +300,7 @@ export default defineComponent({
|
|
|
300
300
|
const objOptions = computed(() => props.Field.Options || undefined);
|
|
301
301
|
|
|
302
302
|
const timeOptions = computed(() => {
|
|
303
|
-
if (objOptions.
|
|
303
|
+
if (objOptions.value) return undefined;
|
|
304
304
|
|
|
305
305
|
if (!props.Field.MinValue && !props.Field.MaxValue) {
|
|
306
306
|
return undefined;
|
|
@@ -349,6 +349,8 @@ export default defineComponent({
|
|
|
349
349
|
})
|
|
350
350
|
|
|
351
351
|
return {
|
|
352
|
+
min,
|
|
353
|
+
max,
|
|
352
354
|
fieldData,
|
|
353
355
|
locale,
|
|
354
356
|
|
|
@@ -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>
|
|
@@ -8,6 +8,9 @@ import { defineComponent } from 'vue';
|
|
|
8
8
|
|
|
9
9
|
export default defineComponent({
|
|
10
10
|
name: 'mourningNode',
|
|
11
|
+
setup() {
|
|
12
|
+
return {};
|
|
13
|
+
},
|
|
11
14
|
mounted() {
|
|
12
15
|
const mourningStore = useMourningStore();
|
|
13
16
|
|
|
@@ -18,8 +21,9 @@ export default defineComponent({
|
|
|
18
21
|
}
|
|
19
22
|
mourningStore.mourning = inMourning;
|
|
20
23
|
|
|
21
|
-
let
|
|
22
|
-
|
|
24
|
+
let bodyElem = document.getElementsByTagName('html')[0];
|
|
25
|
+
let classes = bodyElem.className.split(' ').filter((c) => !!c);
|
|
26
|
+
|
|
23
27
|
if (inMourning) {
|
|
24
28
|
classes.push('mourning-site');
|
|
25
29
|
} else {
|
|
@@ -27,19 +31,20 @@ export default defineComponent({
|
|
|
27
31
|
classes = classes.filter((c) => c.trim() !== 'mourning-site');
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
bodyElem.className = classes.join(' ');
|
|
31
35
|
});
|
|
32
36
|
},
|
|
33
37
|
});
|
|
34
38
|
</script>
|
|
35
39
|
|
|
36
|
-
<style lang="
|
|
37
|
-
.mourning-site
|
|
38
|
-
-webkit-filter: grayscale(100%)
|
|
39
|
-
-moz-filter: grayscale(100%)
|
|
40
|
-
-ms-filter: grayscale(100%)
|
|
41
|
-
-o-filter: grayscale(100%)
|
|
42
|
-
filter: grayscale(100%)
|
|
43
|
-
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)
|
|
44
|
-
filter: gray
|
|
40
|
+
<style lang="scss">
|
|
41
|
+
.mourning-site {
|
|
42
|
+
-webkit-filter: grayscale(100%);
|
|
43
|
+
-moz-filter: grayscale(100%);
|
|
44
|
+
-ms-filter: grayscale(100%);
|
|
45
|
+
-o-filter: grayscale(100%);
|
|
46
|
+
filter: grayscale(100%);
|
|
47
|
+
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
|
|
48
|
+
filter: gray;
|
|
49
|
+
}
|
|
45
50
|
</style>
|