@skyfox2000/webui 1.5.7 → 1.5.10
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/lib/assets/modules/{baseLayout-DfTxHOFc.js → baseLayout-BuQjrozB.js} +9 -9
- package/lib/assets/modules/{file-upload-DTOdV5vM.js → file-upload-DcusqXDb.js} +5 -5
- package/lib/assets/modules/{index-M1qERbea.js → index-BlQB5KSU.js} +2 -2
- package/lib/assets/modules/{index-BwMaOrJT.js → index-CW_ZCHWs.js} +1 -1
- package/lib/assets/modules/index-CekzHbWp.js +114 -0
- package/lib/assets/modules/{menuTabs-DWaBSRNr.js → menuTabs-BYSjomB7.js} +44 -36
- package/lib/assets/modules/{toolIcon-BYnHhAy-.js → toolIcon-D4vAp0qA.js} +1 -1
- package/lib/assets/modules/{upload-template-BKm9mFq8.js → upload-template-NU0Bpg4N.js} +2056 -2176
- package/lib/assets/modules/uploadList-ENSsTfpD.js +472 -0
- package/lib/const/options.d.ts +6 -20
- package/lib/const/stores.d.ts +11 -0
- package/lib/es/AceEditor/index.js +70 -70
- package/lib/es/BasicLayout/index.js +6 -6
- package/lib/es/Error403/index.js +1 -1
- package/lib/es/Error404/index.js +1 -1
- package/lib/es/ExcelForm/index.js +16 -16
- package/lib/es/MenuLayout/index.js +6 -6
- package/lib/es/TemplateFile/index.js +5 -5
- package/lib/es/UploadForm/index.js +5 -5
- package/lib/index.d.ts +2 -1
- package/lib/locales/default.d.ts +137 -115
- package/lib/utils/tools.d.ts +1 -0
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +1692 -1547
- package/package.json +1 -1
- package/src/components/content/dialog/index.vue +1 -0
- package/src/components/content/form/formItem.vue +3 -2
- package/src/components/content/search/index.vue +1 -0
- package/src/components/content/search/searchItem.vue +3 -2
- package/src/components/form/aceEditor/index.vue +5 -3
- package/src/components/form/cascader/index.vue +5 -3
- package/src/components/form/checkbox/index.vue +1 -1
- package/src/components/form/datePicker/index.vue +2 -1
- package/src/components/form/input/index.vue +1 -1
- package/src/components/form/input/inputNumber.vue +3 -1
- package/src/components/form/input/inputPassword.vue +3 -1
- package/src/components/form/propEditor/index.vue +8 -3
- package/src/components/form/radio/index.vue +2 -1
- package/src/components/form/radio/radioStatus.vue +2 -1
- package/src/components/form/switch/index.vue +3 -1
- package/src/components/form/textarea/index.vue +1 -1
- package/src/components/form/timePicker/index.vue +4 -1
- package/src/components/form/treeSelect/index.vue +3 -1
- package/src/components/form/upload/imageList.vue +8 -6
- package/src/components/form/upload/uploadList.vue +6 -5
- package/src/components/layout/datetime/index.vue +15 -4
- package/src/components/layout/header/language.vue +2 -0
- package/src/const/options.ts +76 -52
- package/src/const/stores.ts +58 -0
- package/src/index.ts +2 -0
- package/src/locales/default.ts +145 -123
- package/src/locales/en-US.json +320 -0
- package/src/locales/index.ts +109 -39
- package/src/stores/hostInfo.ts +2 -19
- package/src/stores/userInfo.ts +2 -30
- package/src/utils/options.ts +2 -2
- package/src/utils/tools.ts +88 -83
- package/lib/assets/modules/index-BDoBUrYA.js +0 -114
- package/lib/assets/modules/uploadList-CHvr6Hp1.js +0 -472
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import { Button } from '../../common';
|
|
|
4
4
|
import { Modal, Space } from 'ant-design-vue';
|
|
5
5
|
import { onFormSave, onFormSaveAs, onFormClose, EditorControl, ProviderKeys } from '@/index';
|
|
6
6
|
import { AnyData } from '@skyfox2000/fapi';
|
|
7
|
+
import { $t } from '@/locales/index';
|
|
7
8
|
|
|
8
9
|
const props = defineProps<{
|
|
9
10
|
/**
|
|
@@ -5,6 +5,7 @@ import { Helper } from '../../common';
|
|
|
5
5
|
import { computed, inject, ref, useAttrs } from 'vue';
|
|
6
6
|
import { AnyData } from '@skyfox2000/fapi';
|
|
7
7
|
import { getRule } from '@/utils/form-validate';
|
|
8
|
+
import { $t } from '@/locales/index';
|
|
8
9
|
|
|
9
10
|
const props = defineProps<{
|
|
10
11
|
/**
|
|
@@ -62,9 +63,9 @@ const required = computed(() => {
|
|
|
62
63
|
// 如果rule包含.,则表示是对象属性
|
|
63
64
|
const rule = getRule(props.rule.split('.'), editorCtrl?.formRules?.value);
|
|
64
65
|
if (!rule) {
|
|
65
|
-
message.error(
|
|
66
|
+
message.error($t('webui.components.content.formItem.validationRuleNotFound', { label: props.label, rule: props.rule }));
|
|
66
67
|
errInfo.value.errClass = 'text-[#ff4d4f]';
|
|
67
|
-
errInfo.value.msg =
|
|
68
|
+
errInfo.value.msg = $t('webui.components.content.formItem.validationRuleNotFound', { label: props.label, rule: props.rule });
|
|
68
69
|
return true;
|
|
69
70
|
}
|
|
70
71
|
if (!rule.required) {
|
|
@@ -5,6 +5,7 @@ import { FormItem } from 'ant-design-vue';
|
|
|
5
5
|
import { AnyData } from '@skyfox2000/fapi';
|
|
6
6
|
import { getRule } from '@/utils/form-validate';
|
|
7
7
|
import message from 'vue-m-message';
|
|
8
|
+
import { $t } from '@/locales/index';
|
|
8
9
|
|
|
9
10
|
const props = defineProps<{
|
|
10
11
|
/**
|
|
@@ -42,9 +43,9 @@ const required = computed(() => {
|
|
|
42
43
|
// 如果rule包含.,则表示是对象属性
|
|
43
44
|
const rule = getRule(props.rule.split('.'), editorCtrl?.formRules?.value);
|
|
44
45
|
if (!rule) {
|
|
45
|
-
message.error(
|
|
46
|
+
message.error($t('webui.components.content.searchItem.validationRuleNotFound', { label: props.label, rule: props.rule }));
|
|
46
47
|
errInfo.value.errClass = 'text-[#ff4d4f]';
|
|
47
|
-
errInfo.value.msg =
|
|
48
|
+
errInfo.value.msg = $t('webui.components.content.searchItem.validationRuleNotFound', { label: props.label, rule: props.rule });
|
|
48
49
|
return true;
|
|
49
50
|
}
|
|
50
51
|
if (!rule.required) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { onMounted, ref, watch, defineAsyncComponent } from 'vue';
|
|
3
3
|
import { ToolIcon, Dialog } from '../../index';
|
|
4
|
+
import { $t } from '@/locales/index';
|
|
4
5
|
import { loadTheme, loadWorker, ensureAceLoaded } from './aceConfig';
|
|
5
6
|
|
|
6
7
|
const props = defineProps<{
|
|
@@ -160,16 +161,17 @@ onMounted(async () => {
|
|
|
160
161
|
<div class="flex-1 overflow-hidden">
|
|
161
162
|
<VAceEditor v-if="editorLoaded" :class="[height]" v-model:value="content" :lang="language" :theme="theme"
|
|
162
163
|
:options="aceOptions" @blur="handleBlur" @keyup.enter.native.stop @keydown.enter.native.stop />
|
|
163
|
-
<div v-else :class="[height, 'flex justify-center items-center']"
|
|
164
|
+
<div v-else :class="[height, 'flex justify-center items-center']">{{
|
|
165
|
+
$t('webui.components.form.aceEditor.loading') }}</div>
|
|
164
166
|
</div>
|
|
165
167
|
</div>
|
|
166
|
-
<Dialog title="
|
|
168
|
+
<Dialog :title="$t('webui.components.form.aceEditor.title')" v-model:open="isFullScreen" :width="680" :footer="null">
|
|
167
169
|
<VAceEditor v-if="isFullScreen && editorLoaded" class="h-[500px] w-[99.3%] border-1 border-solid border-gray-200"
|
|
168
170
|
v-model:value="content" :lang="language" :theme="theme" :options="aceOptions" @blur="handleBlur"
|
|
169
171
|
@keyup.enter.native.stop @keydown.enter.native.stop />
|
|
170
172
|
<div v-else-if="isFullScreen"
|
|
171
173
|
class="h-[500px] w-[99.3%] flex justify-center items-center border-1 border-solid border-gray-200">
|
|
172
|
-
|
|
174
|
+
{{ $t('webui.components.form.aceEditor.loading') }}
|
|
173
175
|
</div>
|
|
174
176
|
</Dialog>
|
|
175
177
|
</template>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, onMounted, onUnmounted, useAttrs, watch, shallowRef, onActivated } from 'vue';
|
|
3
|
+
import { $t } from '@/locales/index';
|
|
3
4
|
import {
|
|
4
5
|
circleLoading,
|
|
5
6
|
useInputFactory,
|
|
@@ -45,7 +46,7 @@ watch(
|
|
|
45
46
|
() => url.value.loading,
|
|
46
47
|
(newVal) => {
|
|
47
48
|
if (newVal) placeholder.value = '';
|
|
48
|
-
else if (!placeholder.value) placeholder.value = '
|
|
49
|
+
else if (!placeholder.value) placeholder.value = $t('webui.components.form.cascader.pleaseSelect', [labelText.value]);
|
|
49
50
|
},
|
|
50
51
|
{ immediate: true },
|
|
51
52
|
);
|
|
@@ -110,10 +111,11 @@ onUnmounted(() => {
|
|
|
110
111
|
<div class="relative w-[248px] max-w-[248px]">
|
|
111
112
|
<div v-if="!selectOptions.length" class="absolute z-10 mt-[5px] mr-[10px] text-[#999] flex items-center">
|
|
112
113
|
<circleLoading class="text-[#555] mx-[5px] !ml-[10px] !w-4 !h-4" />
|
|
113
|
-
<span
|
|
114
|
+
<span>{{ $t('webui.components.form.cascader.loading') }}</span>
|
|
114
115
|
</div>
|
|
115
116
|
<Cascader :options="selectOptions" :class="[errInfo?.errClass]" :allow-clear="true"
|
|
116
|
-
:placeholder="selectOptions.length > 0 ? '
|
|
117
|
+
:placeholder="selectOptions.length > 0 ? $t('webui.components.form.cascader.pleaseSelect', [labelText]) : ''"
|
|
118
|
+
@change="onChanged" v-bind="attrs" />
|
|
117
119
|
</div>
|
|
118
120
|
</template>
|
|
119
121
|
|
|
@@ -99,7 +99,7 @@ onUnmounted(() => {
|
|
|
99
99
|
<!-- TODO 获取结果通知 -->
|
|
100
100
|
<!-- <div v-if="!checkboxOptions.length" class="absolute z-10 mt-[5px] mr-[10px] text-[#999] flex items-center">
|
|
101
101
|
<circleLoading class="text-[#555] mx-[5px] !ml-[10px] !w-4 !h-4" />
|
|
102
|
-
<span
|
|
102
|
+
<span>{{ $t('webui.components.form.checkbox.loading') }}</span>
|
|
103
103
|
</div> -->
|
|
104
104
|
<CheckboxGroup @change="onChanged" class="w-full mb-[-3px]" v-bind="attrs">
|
|
105
105
|
<template v-if="checkboxOptions.length > 0">
|
|
@@ -3,6 +3,7 @@ import { ref } from 'vue';
|
|
|
3
3
|
import { DatePicker } from 'ant-design-vue';
|
|
4
4
|
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN';
|
|
5
5
|
import { formValidate, useInputFactory } from '@/index';
|
|
6
|
+
import { $t } from '@/locales/index';
|
|
6
7
|
const props = defineProps<{
|
|
7
8
|
valueFormat?: string;
|
|
8
9
|
}>();
|
|
@@ -21,7 +22,7 @@ const dateFormat = ref<string>(props.valueFormat ?? 'YYYY-MM-DD');
|
|
|
21
22
|
<DatePicker
|
|
22
23
|
class="w-full"
|
|
23
24
|
:class="[errInfo?.errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '']"
|
|
24
|
-
:placeholder="'
|
|
25
|
+
:placeholder="$t('webui.components.form.datePicker.pleaseSelect', [labelText])"
|
|
25
26
|
:locale="locale"
|
|
26
27
|
:valueFormat="dateFormat"
|
|
27
28
|
@blur="onBlur"
|
|
@@ -70,7 +70,7 @@ const onClear = () => {
|
|
|
70
70
|
v-model:value="innerValue"
|
|
71
71
|
autocomplete="new-password"
|
|
72
72
|
:allow-clear="true"
|
|
73
|
-
:placeholder="t('webui.
|
|
73
|
+
:placeholder="t('webui.common.placeholder', [labelText])"
|
|
74
74
|
@blur="onBlur"
|
|
75
75
|
@change="onClear"
|
|
76
76
|
v-bind="$attrs"
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { formValidate, useInputFactory } from '@/index';
|
|
3
3
|
import { InputNumber } from 'ant-design-vue';
|
|
4
|
+
import { useI18n } from 'vue-i18n';
|
|
4
5
|
|
|
5
6
|
const { editorCtrl, labelText, errInfo } = useInputFactory();
|
|
7
|
+
const { t } = useI18n();
|
|
6
8
|
const onBlur = () => {
|
|
7
9
|
if (errInfo?.value.errClass && editorCtrl) {
|
|
8
10
|
/// 重新开始验证
|
|
@@ -15,7 +17,7 @@ const onBlur = () => {
|
|
|
15
17
|
:class="[errInfo?.errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '']"
|
|
16
18
|
@blur="onBlur"
|
|
17
19
|
:allow-clear="false"
|
|
18
|
-
|
|
20
|
+
:placeholder="t('webui.common.placeholder', [labelText])"
|
|
19
21
|
class="w-[50%]"
|
|
20
22
|
v-bind="$attrs"
|
|
21
23
|
>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { formValidate, useInputFactory } from '@/index';
|
|
3
3
|
import { InputPassword } from 'ant-design-vue';
|
|
4
|
+
import { useI18n } from 'vue-i18n';
|
|
4
5
|
|
|
5
6
|
const { editorCtrl, labelText, errInfo } = useInputFactory();
|
|
7
|
+
const { t } = useI18n();
|
|
6
8
|
const onBlur = () => {
|
|
7
9
|
if (errInfo?.value.errClass && editorCtrl) {
|
|
8
10
|
/// 重新开始验证
|
|
@@ -15,7 +17,7 @@ const onBlur = () => {
|
|
|
15
17
|
:class="errInfo?.errClass === 'error' ? ['error', '!border-red-300', 'shadow-[0_0_3px_0px_#ff4d4f]'] : ''"
|
|
16
18
|
:allow-clear="true"
|
|
17
19
|
autocomplete="new-password"
|
|
18
|
-
|
|
20
|
+
:placeholder="t('webui.common.placeholder', [labelText])"
|
|
19
21
|
@blur="onBlur"
|
|
20
22
|
v-bind="$attrs"
|
|
21
23
|
/>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ref, watch } from 'vue';
|
|
3
3
|
import { Input, Button } from 'ant-design-vue';
|
|
4
4
|
import type { PropConfigItem } from '@/typings/form.d';
|
|
5
|
+
import { useI18n } from 'vue-i18n';
|
|
5
6
|
|
|
6
7
|
const props = defineProps<{
|
|
7
8
|
/**
|
|
@@ -85,6 +86,8 @@ watch(
|
|
|
85
86
|
{ immediate: true },
|
|
86
87
|
);
|
|
87
88
|
|
|
89
|
+
const { t } = useI18n();
|
|
90
|
+
|
|
88
91
|
const updateConfig = () => {
|
|
89
92
|
let newConfig: Record<string, string>;
|
|
90
93
|
|
|
@@ -140,7 +143,8 @@ const handleInputChange = () => {
|
|
|
140
143
|
<div v-for="item in configList" :key="item.id" class="flex items-center gap-2">
|
|
141
144
|
<div :class="[fieldWidth ? `w-[${fieldWidth}%]` : 'w-[33%]']">
|
|
142
145
|
<Input v-if="!selectList || selectList.length === 0" v-model:value="item.field"
|
|
143
|
-
:title="item.text || item.field" class="w-full"
|
|
146
|
+
:title="item.text || item.field" class="w-full"
|
|
147
|
+
:placeholder="item.text || labelHolder || t('webui.components.form.propEditor.configName')"
|
|
144
148
|
@input="handleInputChange" :disabled="!addMore" />
|
|
145
149
|
<div v-else>
|
|
146
150
|
<Input v-model:value="item.text" :title="item.text" :disabled="true" class="w-[100%]" />
|
|
@@ -149,14 +153,15 @@ const handleInputChange = () => {
|
|
|
149
153
|
</div>
|
|
150
154
|
<div class="w-[3%]">=</div>
|
|
151
155
|
<div :class="[fieldWidth ? `w-[${97 - fieldWidth}%]` : 'w-[64%]']">
|
|
152
|
-
<Input v-model:value="item.value"
|
|
156
|
+
<Input v-model:value="item.value"
|
|
157
|
+
:placeholder="valueHolder || t('webui.common.placeholder', [item.text || t('webui.components.form.propEditor.configValue')])"
|
|
153
158
|
@input="handleInputChange" :title="item.value" />
|
|
154
159
|
</div>
|
|
155
160
|
</div>
|
|
156
161
|
<Button v-if="addMore" @click="addNewLine"
|
|
157
162
|
class="mt-1 w-[80px] !text-[12px] text-[#666] bg-[#e6f7ff] border-[#b3e0ff] hover:bg-[#b3e0ff] hover:border-[#8abeff]"
|
|
158
163
|
size="small">
|
|
159
|
-
|
|
164
|
+
{{ t('webui.components.form.propEditor.addConfigRow') }}
|
|
160
165
|
</Button>
|
|
161
166
|
</div>
|
|
162
167
|
</template>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, onMounted, onUnmounted, watch, useAttrs, shallowRef, onActivated } from 'vue';
|
|
3
|
+
import { $t } from '@/locales/index';
|
|
3
4
|
import { Radio, RadioChangeEvent, RadioGroup } from 'ant-design-vue';
|
|
4
5
|
import {
|
|
5
6
|
OptionCommProps,
|
|
@@ -22,7 +23,7 @@ const props = defineProps({
|
|
|
22
23
|
},
|
|
23
24
|
nodata: {
|
|
24
25
|
type: String,
|
|
25
|
-
default: '
|
|
26
|
+
default: $t('webui.components.form.radio.noData'),
|
|
26
27
|
},
|
|
27
28
|
/**
|
|
28
29
|
* 换行数量
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ref, PropType } from 'vue';
|
|
3
3
|
import Radio from './index.vue';
|
|
4
4
|
import { OPTIONS } from '@/index';
|
|
5
|
+
import { $t } from '@/locales/index';
|
|
5
6
|
|
|
6
7
|
const props = defineProps({
|
|
7
8
|
/**
|
|
@@ -31,7 +32,7 @@ const props = defineProps({
|
|
|
31
32
|
const options = ref(JSON.parse(JSON.stringify(OPTIONS.getOptions(props.dataKey))));
|
|
32
33
|
if (props.all === true) {
|
|
33
34
|
options.value.unshift({
|
|
34
|
-
label: '
|
|
35
|
+
label: $t('webui.components.form.radio.all'),
|
|
35
36
|
value: props.allValue || [0, 1],
|
|
36
37
|
});
|
|
37
38
|
}
|
|
@@ -5,6 +5,7 @@ import { Switch } from 'ant-design-vue';
|
|
|
5
5
|
import message from 'vue-m-message';
|
|
6
6
|
import { useOptionFactory } from '@/utils/page';
|
|
7
7
|
import { computed } from 'vue';
|
|
8
|
+
import { useI18n } from 'vue-i18n';
|
|
8
9
|
|
|
9
10
|
const props = defineProps({
|
|
10
11
|
...OptionCommProps,
|
|
@@ -47,6 +48,7 @@ const emit = defineEmits<{
|
|
|
47
48
|
}>();
|
|
48
49
|
|
|
49
50
|
const { editorCtrl, errInfo } = useInputFactory();
|
|
51
|
+
const { t } = useI18n();
|
|
50
52
|
|
|
51
53
|
const customSize = computed(() => {
|
|
52
54
|
switch (props.size) {
|
|
@@ -66,7 +68,7 @@ const onChange = (checked: boolean | string | number) => {
|
|
|
66
68
|
onMounted(() => {
|
|
67
69
|
if (!props.data || props.data.length != 2) {
|
|
68
70
|
console.error('Switch组件: ', props.data);
|
|
69
|
-
message.error('
|
|
71
|
+
message.error(t('webui.components.form.switch.error'));
|
|
70
72
|
return;
|
|
71
73
|
}
|
|
72
74
|
if (optionCtrl) loadOption(optionCtrl.autoload, optionCtrl, props);
|
|
@@ -16,7 +16,7 @@ const onBlur = () => {
|
|
|
16
16
|
<Textarea
|
|
17
17
|
:class="errInfo?.errClass === 'error' ? ['error', '!border-red-300', 'shadow-[0_0_3px_0px_#ff4d4f]'] : ''"
|
|
18
18
|
:allow-clear="true"
|
|
19
|
-
:placeholder="t('webui.
|
|
19
|
+
:placeholder="t('webui.common.placeholder', [labelText])"
|
|
20
20
|
@blur="onBlur"
|
|
21
21
|
@keyup.enter.native.stop
|
|
22
22
|
@keydown.enter.native.stop
|
|
@@ -3,11 +3,13 @@ import { ref } from 'vue';
|
|
|
3
3
|
import { TimePicker } from 'ant-design-vue';
|
|
4
4
|
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN';
|
|
5
5
|
import { formValidate, useInputFactory } from '@/index';
|
|
6
|
+
import { useI18n } from 'vue-i18n';
|
|
6
7
|
const props = defineProps<{
|
|
7
8
|
valueFormat?: string;
|
|
8
9
|
}>();
|
|
9
10
|
|
|
10
11
|
const { editorCtrl, labelText, errInfo } = useInputFactory();
|
|
12
|
+
const { t } = useI18n();
|
|
11
13
|
const onBlur = () => {
|
|
12
14
|
if (errInfo?.value.errClass && editorCtrl) {
|
|
13
15
|
/// 重新开始验证
|
|
@@ -20,5 +22,6 @@ const timeFormat = ref<string>(props.valueFormat ?? 'HH:mm');
|
|
|
20
22
|
<template>
|
|
21
23
|
<TimePicker class="w-full"
|
|
22
24
|
:class="[errInfo?.errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '']"
|
|
23
|
-
:placeholder="'
|
|
25
|
+
:placeholder="t('webui.common.pleaseSelect') + labelText" :locale="locale" :valueFormat="timeFormat"
|
|
26
|
+
@blur="onBlur" />
|
|
24
27
|
</template>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { ref, watch, onMounted, PropType, onActivated } from 'vue';
|
|
3
|
+
import { $t } from '@/locales/index';
|
|
3
4
|
import { TreeSelect } from 'ant-design-vue';
|
|
4
5
|
import type { SelectValue, TreeControl, TreeNode } from '@/index';
|
|
5
6
|
import { queryTree, useInputFactory } from '@/index';
|
|
@@ -116,7 +117,8 @@ const onClear = () => {
|
|
|
116
117
|
|
|
117
118
|
<template>
|
|
118
119
|
<TreeSelect :class="[errInfo?.errClass]" tree-line :multiple="multiple" :tree-default-expanded-keys="['-']"
|
|
119
|
-
v-model:value="currentValue" :tree-data="selectTreeData"
|
|
120
|
+
v-model:value="currentValue" :tree-data="selectTreeData"
|
|
121
|
+
:placeholder="$t('webui.components.form.treeSelect.pleaseSelect', [labelText])" class="w-full"
|
|
120
122
|
@change="handleChange" @clear="onClear" v-bind="$attrs" />
|
|
121
123
|
</template>
|
|
122
124
|
<style scoped>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ToolIcon } from '../../common';
|
|
3
3
|
import { computed, ref, watch } from 'vue';
|
|
4
4
|
import message from 'vue-m-message';
|
|
5
|
+
import { useI18n } from 'vue-i18n';
|
|
5
6
|
import type { UploadProps } from 'ant-design-vue';
|
|
6
7
|
import { Upload, Image } from 'ant-design-vue';
|
|
7
8
|
import { UploadFile, path } from '@/index';
|
|
@@ -85,6 +86,7 @@ const props = withDefaults(defineProps<ImageListProps>(), {
|
|
|
85
86
|
|
|
86
87
|
const inputFactory = useInputFactory();
|
|
87
88
|
const { errInfo } = inputFactory;
|
|
89
|
+
const { t } = useI18n();
|
|
88
90
|
|
|
89
91
|
// Upload 组件的文件列表更新
|
|
90
92
|
const displayList = ref<UploadFile[]>(props.fileList);
|
|
@@ -101,14 +103,14 @@ const validateFile = (file: File): boolean => {
|
|
|
101
103
|
if (props.fileExt && props.fileExt.length > 0) {
|
|
102
104
|
const extension = file.name.split('.').pop()?.toLowerCase() || '';
|
|
103
105
|
if (!props.fileExt.includes(extension)) {
|
|
104
|
-
message.error('
|
|
106
|
+
message.error(t('webui.components.form.upload.unsupportedFileType'));
|
|
105
107
|
return false;
|
|
106
108
|
}
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
// 文件大小验证
|
|
110
112
|
if (file.size / 1024 / 1024 > props.maxFileSize) {
|
|
111
|
-
message.error(
|
|
113
|
+
message.error(t('webui.components.form.upload.fileSizeExceeded', [props.maxFileSize]));
|
|
112
114
|
return false;
|
|
113
115
|
}
|
|
114
116
|
|
|
@@ -161,7 +163,7 @@ const handleFileSelect = async (newFiles: any[]) => {
|
|
|
161
163
|
|
|
162
164
|
// 检查是否达到最大数量限制
|
|
163
165
|
if (isMaxCountReached()) {
|
|
164
|
-
message.error(
|
|
166
|
+
message.error(t('webui.components.form.upload.maxFileCount', [props.maxCount]));
|
|
165
167
|
hasError = true;
|
|
166
168
|
break;
|
|
167
169
|
}
|
|
@@ -260,7 +262,7 @@ const removeFile = (index: number) => {
|
|
|
260
262
|
},
|
|
261
263
|
}).then((res) => {
|
|
262
264
|
if (res && res.status === ResStatus.SUCCESS) {
|
|
263
|
-
message.success('
|
|
265
|
+
message.success(t('webui.common.success'));
|
|
264
266
|
displayList.value.splice(index, 1);
|
|
265
267
|
}
|
|
266
268
|
});
|
|
@@ -342,12 +344,12 @@ const hoveredIndex = ref(-1);
|
|
|
342
344
|
<div v-if="previewUrl" class="flex items-center text-white cursor-pointer hover:text-blue-400"
|
|
343
345
|
@click="previewFile(index)">
|
|
344
346
|
<ToolIcon icon="icon-eye" clickable />
|
|
345
|
-
<span class="text-sm ml-1"
|
|
347
|
+
<span class="text-sm ml-1">{{ t('webui.components.form.upload.preview') }}</span>
|
|
346
348
|
</div>
|
|
347
349
|
<div v-if="showDelete !== false" class="flex items-center text-white cursor-pointer hover:text-red-400"
|
|
348
350
|
@click="removeFile(index)">
|
|
349
351
|
<ToolIcon icon="icon-new" :angle="45" clickable />
|
|
350
|
-
<span class="text-sm ml-1"
|
|
352
|
+
<span class="text-sm ml-1">{{ t('webui.components.form.upload.delete') }}</span>
|
|
351
353
|
</div>
|
|
352
354
|
</div>
|
|
353
355
|
</div>
|
|
@@ -369,9 +369,9 @@ const confirmIndex = (index: number) => {
|
|
|
369
369
|
|
|
370
370
|
const getPlaceholder = (): string => {
|
|
371
371
|
const typeMsg =
|
|
372
|
-
props.fileExt && props.fileExt.length && props.fileExtTip ?
|
|
373
|
-
const sizeMsg = props.maxFileSize !== 0 && props.maxFileSizeTip ?
|
|
374
|
-
const countMsg = props.maxCount !== 0 && props.maxCountTip ?
|
|
372
|
+
props.fileExt && props.fileExt.length && props.fileExtTip ? $t('webui.components.form.upload.fileTypeRequired', [props.fileExt.join('/')]) : '';
|
|
373
|
+
const sizeMsg = props.maxFileSize !== 0 && props.maxFileSizeTip ? $t('webui.components.form.upload.singleFileMax', [props.maxFileSize]) : '';
|
|
374
|
+
const countMsg = props.maxCount !== 0 && props.maxCountTip ? $t('webui.components.form.upload.maxFiles', [props.maxCount]) : '';
|
|
375
375
|
|
|
376
376
|
return [sizeMsg, typeMsg, countMsg].filter(Boolean).join(',');
|
|
377
377
|
};
|
|
@@ -473,7 +473,7 @@ const getStatus = (status?: UploadStatus) => {
|
|
|
473
473
|
clickable @click="previewFile(index)" />
|
|
474
474
|
<span v-if="showActionText" class="mr-2 text-sm text-nowrap"
|
|
475
475
|
v-auth="{ role: ['Super', 'Admin'], permit: ':uploadlist:preview' }"
|
|
476
|
-
@click="previewFile(index)"
|
|
476
|
+
@click="previewFile(index)">{{ $t('webui.common.preview') }}</span>
|
|
477
477
|
</Tooltip>
|
|
478
478
|
</div>
|
|
479
479
|
<div v-if="showDelete !== false"
|
|
@@ -487,7 +487,8 @@ const getStatus = (status?: UploadStatus) => {
|
|
|
487
487
|
<ToolIcon icon="icon-new" :angle="45"
|
|
488
488
|
v-auth="{ role: ['Super', 'Admin'], permit: ':uploadlist:delete' }" clickable />
|
|
489
489
|
<span v-if="showActionText" class="text-sm text-nowrap"
|
|
490
|
-
v-auth="{ role: ['Super', 'Admin'], permit: ':uploadlist:delete' }"
|
|
490
|
+
v-auth="{ role: ['Super', 'Admin'], permit: ':uploadlist:delete' }">{{
|
|
491
|
+
$t('webui.common.delete') }}</span>
|
|
491
492
|
</div>
|
|
492
493
|
</Tooltip>
|
|
493
494
|
</Popconfirm>
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { ref, onMounted } from 'vue'
|
|
3
|
+
import { getLang } from '@/locales/index'
|
|
4
|
+
|
|
3
5
|
const DateTime = ref("")
|
|
6
|
+
|
|
4
7
|
onMounted(() => {
|
|
5
8
|
setInterval(() => {
|
|
6
9
|
const curTime = new Date()
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const lang = getLang()
|
|
11
|
+
const options: Intl.DateTimeFormatOptions = {
|
|
12
|
+
year: 'numeric',
|
|
13
|
+
month: '2-digit',
|
|
14
|
+
day: '2-digit',
|
|
15
|
+
hour: '2-digit',
|
|
16
|
+
minute: '2-digit',
|
|
17
|
+
second: '2-digit',
|
|
18
|
+
hour12: false
|
|
19
|
+
}
|
|
20
|
+
DateTime.value = curTime.toLocaleString(lang, options)
|
|
21
|
+
}, 1000)
|
|
11
22
|
})
|
|
12
23
|
</script>
|
|
13
24
|
|