@scx-js/scx-admin 0.0.3
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/crud/crud-add-button.vue +28 -0
- package/components/crud/crud-batch-delete.vue +27 -0
- package/components/crud/crud-edit-dialog.vue +36 -0
- package/components/crud/crud-edit-form.vue +28 -0
- package/components/crud/crud-form-footer.vue +28 -0
- package/components/crud/crud-pagination.vue +51 -0
- package/components/crud/crud-reset-button.vue +19 -0
- package/components/crud/crud-search-button.vue +25 -0
- package/components/crud/crud-table-delete-button.vue +31 -0
- package/components/crud/crud-table-edit-button.vue +26 -0
- package/components/crud/crud-table.vue +131 -0
- package/components/crud/index.css +46 -0
- package/components/crud/index.vue +37 -0
- package/components/easy-ckeditor/default-editor-config.js +199 -0
- package/components/easy-ckeditor/easy-ckeditor-lazy.css +17 -0
- package/components/easy-ckeditor/easy-ckeditor-lazy.vue +106 -0
- package/components/easy-ckeditor/index.css +3 -0
- package/components/easy-ckeditor/index.vue +58 -0
- package/components/easy-ckeditor/plugins/scx-upload-adapter.js +39 -0
- package/components/easy-form-item/index.vue +168 -0
- package/components/easy-image/index.css +24 -0
- package/components/easy-image/index.vue +75 -0
- package/components/easy-monaco-editor/index.css +8 -0
- package/components/easy-monaco-editor/index.vue +70 -0
- package/components/easy-monaco-editor/use-worker.js +27 -0
- package/components/easy-select/index.vue +29 -0
- package/components/easy-upload/index.vue +94 -0
- package/components/easy-upload-list/index.vue +107 -0
- package/components/index.js +69 -0
- package/components/left-tree/index.css +74 -0
- package/components/left-tree/index.vue +130 -0
- package/components/scx-container/index.css +19 -0
- package/components/scx-container/index.vue +22 -0
- package/components/user-profile/change-password-dialog.vue +100 -0
- package/components/user-profile/change-user-avatar.vue +43 -0
- package/components/user-profile/change-username-dialog.vue +82 -0
- package/components/user-profile/index.css +8 -0
- package/components/user-profile/index.vue +77 -0
- package/index.js +4 -0
- package/layout/img/default-avatar.gif +0 -0
- package/layout/index.vue +24 -0
- package/layout/scx-app.vue +110 -0
- package/layout/scx-input.vue +84 -0
- package/layout/scx-logo.vue +65 -0
- package/layout/scx-main.vue +48 -0
- package/layout/scx-menu-item.vue +47 -0
- package/layout/scx-menu-toggle.vue +69 -0
- package/layout/scx-menu.vue +122 -0
- package/layout/scx-navbar.vue +47 -0
- package/layout/scx-notice.vue +211 -0
- package/layout/scx-sidebar.vue +70 -0
- package/layout/scx-theme-switch.vue +54 -0
- package/layout/scx-user-panel.vue +193 -0
- package/package.json +30 -0
- package/routes.js +57 -0
- package/scx/ali-oss.js +87 -0
- package/scx/auth-fetch.js +68 -0
- package/scx/crud-context.js +522 -0
- package/scx/easy-option.js +131 -0
- package/scx/index.js +8 -0
- package/scx/scx-auth-info.js +48 -0
- package/scx/scx-auth.js +197 -0
- package/scx/scx-config-manager.js +105 -0
- package/scx/scx-router.js +273 -0
- package/styles/index.css +37 -0
- package/util/cities.js +350 -0
- package/util/duration-format.js +27 -0
- package/util/element-plus-helper.js +114 -0
- package/util/get-order-number.js +7 -0
- package/util/index.js +4 -0
- package/util/nations.js +16 -0
- package/util/provinces.js +41 -0
- package/views/error-page.vue +79 -0
- package/views/login/index.css +95 -0
- package/views/login/login-and-register.vue +66 -0
- package/views/login/login-bg.vue +121 -0
- package/views/login/login-form-bg.vue +61 -0
- package/views/login/login-form.vue +137 -0
- package/views/login/login-message.js +28 -0
- package/views/login/login.vue +29 -0
- package/views/login/register-form.vue +148 -0
- package/views/no-perm.vue +7 -0
- package/views/not-found.vue +7 -0
- package/views/rocket.vue +84 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
import {
|
2
|
+
Alignment,
|
3
|
+
AutoImage,
|
4
|
+
AutoLink,
|
5
|
+
BlockQuote,
|
6
|
+
Bold,
|
7
|
+
Code,
|
8
|
+
CodeBlock,
|
9
|
+
Essentials,
|
10
|
+
FindAndReplace,
|
11
|
+
Font,
|
12
|
+
Heading,
|
13
|
+
Highlight,
|
14
|
+
HorizontalLine,
|
15
|
+
Image,
|
16
|
+
ImageCaption,
|
17
|
+
ImageInsert,
|
18
|
+
ImageResize,
|
19
|
+
ImageStyle,
|
20
|
+
ImageToolbar,
|
21
|
+
ImageUpload,
|
22
|
+
Indent,
|
23
|
+
IndentBlock,
|
24
|
+
Italic,
|
25
|
+
Link,
|
26
|
+
LinkImage,
|
27
|
+
List,
|
28
|
+
ListProperties,
|
29
|
+
MediaEmbed,
|
30
|
+
PasteFromOffice,
|
31
|
+
PictureEditing,
|
32
|
+
RemoveFormat,
|
33
|
+
SourceEditing,
|
34
|
+
Strikethrough,
|
35
|
+
Subscript,
|
36
|
+
Superscript,
|
37
|
+
Table,
|
38
|
+
TableCaption,
|
39
|
+
TableCellProperties,
|
40
|
+
TableColumnResize,
|
41
|
+
TableProperties,
|
42
|
+
TableToolbar,
|
43
|
+
Underline,
|
44
|
+
WordCount,
|
45
|
+
} from "ckeditor5";
|
46
|
+
import zhCNTranslations from "ckeditor5/translations/zh-cn.js";
|
47
|
+
|
48
|
+
const defaultEditorConfig = {
|
49
|
+
plugins: [
|
50
|
+
Alignment,
|
51
|
+
AutoImage,
|
52
|
+
AutoLink,
|
53
|
+
BlockQuote,
|
54
|
+
Bold,
|
55
|
+
Code,
|
56
|
+
CodeBlock,
|
57
|
+
List,
|
58
|
+
Heading,
|
59
|
+
Image,
|
60
|
+
ImageCaption,
|
61
|
+
ImageStyle,
|
62
|
+
ImageToolbar,
|
63
|
+
Indent,
|
64
|
+
Italic,
|
65
|
+
Link,
|
66
|
+
MediaEmbed,
|
67
|
+
Table,
|
68
|
+
TableToolbar,
|
69
|
+
Essentials,
|
70
|
+
FindAndReplace,
|
71
|
+
Font,
|
72
|
+
Highlight,
|
73
|
+
HorizontalLine,
|
74
|
+
ImageInsert,
|
75
|
+
ImageResize,
|
76
|
+
ImageUpload,
|
77
|
+
IndentBlock,
|
78
|
+
LinkImage,
|
79
|
+
ListProperties,
|
80
|
+
PasteFromOffice,
|
81
|
+
PictureEditing,
|
82
|
+
RemoveFormat,
|
83
|
+
SourceEditing,
|
84
|
+
Strikethrough,
|
85
|
+
Subscript,
|
86
|
+
Superscript,
|
87
|
+
TableCaption,
|
88
|
+
TableCellProperties,
|
89
|
+
TableColumnResize,
|
90
|
+
TableProperties,
|
91
|
+
Underline,
|
92
|
+
WordCount,
|
93
|
+
],
|
94
|
+
extraPlugins: [],
|
95
|
+
toolbar: {
|
96
|
+
items: [
|
97
|
+
"undo", "redo",
|
98
|
+
"|",
|
99
|
+
"findAndReplace", "selectAll",
|
100
|
+
"|",
|
101
|
+
"heading",
|
102
|
+
"|",
|
103
|
+
"fontSize", "fontFamily", "fontColor", "fontBackgroundColor",
|
104
|
+
"|",
|
105
|
+
"alignment",
|
106
|
+
"|",
|
107
|
+
"bulletedList", "numberedList", "outdent", "indent",
|
108
|
+
"-",
|
109
|
+
"bold", "italic", "underline",
|
110
|
+
{
|
111
|
+
label: "Formatting",
|
112
|
+
icon: "text",
|
113
|
+
items: ["strikethrough", "subscript", "superscript", "code", "|", "removeFormat"],
|
114
|
+
},
|
115
|
+
"|",
|
116
|
+
"horizontalLine",
|
117
|
+
"|",
|
118
|
+
"link", "insertImage", "insertTable",
|
119
|
+
"|",
|
120
|
+
"highlight", "blockQuote", "mediaEmbed", "codeBlock",
|
121
|
+
"|",
|
122
|
+
"sourceEditing",
|
123
|
+
],
|
124
|
+
shouldNotGroupWhenFull: true,
|
125
|
+
},
|
126
|
+
fontFamily: {
|
127
|
+
supportAllValues: true,
|
128
|
+
},
|
129
|
+
fontSize: {
|
130
|
+
options: [10, 12, 14, "default", 18, 20, 22],
|
131
|
+
supportAllValues: true,
|
132
|
+
},
|
133
|
+
htmlEmbed: {
|
134
|
+
showPreviews: true,
|
135
|
+
},
|
136
|
+
image: {
|
137
|
+
styles: [
|
138
|
+
"alignCenter",
|
139
|
+
"alignLeft",
|
140
|
+
"alignRight",
|
141
|
+
],
|
142
|
+
resizeOptions: [
|
143
|
+
{
|
144
|
+
name: "resizeImage:original",
|
145
|
+
label: "Original",
|
146
|
+
value: null,
|
147
|
+
},
|
148
|
+
{
|
149
|
+
name: "resizeImage:25",
|
150
|
+
label: "25%",
|
151
|
+
value: "25",
|
152
|
+
},
|
153
|
+
{
|
154
|
+
name: "resizeImage:50",
|
155
|
+
label: "50%",
|
156
|
+
value: "50",
|
157
|
+
},
|
158
|
+
{
|
159
|
+
name: "resizeImage:75",
|
160
|
+
label: "75%",
|
161
|
+
value: "75",
|
162
|
+
},
|
163
|
+
],
|
164
|
+
toolbar: [
|
165
|
+
"imageTextAlternative", "toggleImageCaption", "|",
|
166
|
+
"imageStyle:inline", "imageStyle:wrapText", "imageStyle:breakText", "imageStyle:side", "|",
|
167
|
+
"resizeImage",
|
168
|
+
],
|
169
|
+
},
|
170
|
+
list: {
|
171
|
+
properties: {
|
172
|
+
styles: true,
|
173
|
+
startIndex: true,
|
174
|
+
reversed: true,
|
175
|
+
},
|
176
|
+
},
|
177
|
+
link: {
|
178
|
+
decorators: {
|
179
|
+
addTargetToExternalLinks: true,
|
180
|
+
defaultProtocol: "https://",
|
181
|
+
toggleDownloadable: {
|
182
|
+
mode: "manual",
|
183
|
+
label: "Downloadable",
|
184
|
+
attributes: {
|
185
|
+
download: "file",
|
186
|
+
},
|
187
|
+
},
|
188
|
+
},
|
189
|
+
},
|
190
|
+
placeholder: "请输入内容 !!!",
|
191
|
+
table: {
|
192
|
+
contentToolbar: [
|
193
|
+
"tableColumn", "tableRow", "mergeTableCells", "tableProperties", "tableCellProperties", "toggleTableCaption",
|
194
|
+
],
|
195
|
+
},
|
196
|
+
translations: [zhCNTranslations],
|
197
|
+
};
|
198
|
+
|
199
|
+
export {defaultEditorConfig};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
:root {
|
2
|
+
--ck-z-modal: 9999999;
|
3
|
+
}
|
4
|
+
|
5
|
+
.easy-ckeditor-lazy {
|
6
|
+
border: 1px solid var(--scx-text-placeholder-color);
|
7
|
+
border-radius: 2px;
|
8
|
+
width: 100%;
|
9
|
+
min-width: 200px;
|
10
|
+
min-height: 100px;
|
11
|
+
padding: 0 0.6em;
|
12
|
+
background-color: white;
|
13
|
+
}
|
14
|
+
|
15
|
+
.easy-ckeditor-lazy.ck-content:not(.ck-focused) {
|
16
|
+
border-color: var(--scx-text-placeholder-color);
|
17
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
<template>
|
2
|
+
<div ref="editorRef" class="easy-ckeditor-lazy" @click="initCkEditor()">
|
3
|
+
|
4
|
+
</div>
|
5
|
+
</template>
|
6
|
+
|
7
|
+
<script>
|
8
|
+
import "./easy-ckeditor-lazy.css";
|
9
|
+
import {onMounted, ref, watch} from "vue";
|
10
|
+
import {createScxUploadAdapterPlugin} from "./plugins/scx-upload-adapter.js";
|
11
|
+
import {useScxFSS} from "scx-ui/scx/scx-fss";
|
12
|
+
import {InlineEditor} from "ckeditor5";
|
13
|
+
import {debounce} from "lodash-es";
|
14
|
+
import {defaultEditorConfig} from "./default-editor-config.js";
|
15
|
+
|
16
|
+
export default {
|
17
|
+
name: "easy-ckeditor-lazy",
|
18
|
+
props: {
|
19
|
+
modelValue: {
|
20
|
+
type: String,
|
21
|
+
default: "",
|
22
|
+
},
|
23
|
+
config: {}
|
24
|
+
},
|
25
|
+
setup(props, ctx) {
|
26
|
+
|
27
|
+
const editorRef = ref();
|
28
|
+
|
29
|
+
const fss = useScxFSS();
|
30
|
+
|
31
|
+
const scxUploadAdapterPlugin = createScxUploadAdapterPlugin(fss);
|
32
|
+
|
33
|
+
defaultEditorConfig.extraPlugins = [scxUploadAdapterPlugin];
|
34
|
+
|
35
|
+
const editorConfig = Object.assign(defaultEditorConfig, props.config);
|
36
|
+
|
37
|
+
let instance = null;
|
38
|
+
|
39
|
+
let isInit = false;
|
40
|
+
|
41
|
+
let lastEditorData = null;
|
42
|
+
|
43
|
+
function initCkEditor() {
|
44
|
+
if (isInit) {
|
45
|
+
return;
|
46
|
+
} else {
|
47
|
+
isInit = true;
|
48
|
+
}
|
49
|
+
InlineEditor
|
50
|
+
.create(editorRef.value, editorConfig)
|
51
|
+
.then(editor => {
|
52
|
+
|
53
|
+
instance = editor;
|
54
|
+
|
55
|
+
setUpEditorEvents();
|
56
|
+
|
57
|
+
editor.data.set(props.modelValue);
|
58
|
+
|
59
|
+
})
|
60
|
+
.catch(err => {
|
61
|
+
console.error(err);
|
62
|
+
});
|
63
|
+
}
|
64
|
+
|
65
|
+
function setUpEditorEvents() {
|
66
|
+
|
67
|
+
const emitDebouncedInputEvent = debounce(evt => {
|
68
|
+
|
69
|
+
const data = lastEditorData = instance.data.get();
|
70
|
+
|
71
|
+
ctx.emit("update:modelValue", data, evt, instance);
|
72
|
+
ctx.emit("input", data, evt, instance);
|
73
|
+
}, 300, {leading: true});
|
74
|
+
|
75
|
+
instance.model.document.on("change:data", emitDebouncedInputEvent);
|
76
|
+
|
77
|
+
}
|
78
|
+
|
79
|
+
onMounted(() => {
|
80
|
+
watch(() => props.modelValue, (value) => {
|
81
|
+
|
82
|
+
if (isInit) {
|
83
|
+
if (instance && value !== lastEditorData) {
|
84
|
+
instance.data.set(value);
|
85
|
+
}
|
86
|
+
|
87
|
+
} else {
|
88
|
+
editorRef.value.innerHTML = value;
|
89
|
+
}
|
90
|
+
|
91
|
+
}, {immediate: true});
|
92
|
+
});
|
93
|
+
|
94
|
+
return {
|
95
|
+
editorRef,
|
96
|
+
initCkEditor,
|
97
|
+
InlineEditor,
|
98
|
+
editorConfig
|
99
|
+
};
|
100
|
+
}
|
101
|
+
};
|
102
|
+
</script>
|
103
|
+
|
104
|
+
<style>
|
105
|
+
|
106
|
+
</style>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<template>
|
2
|
+
<ckeditor v-model="editorData" :config="editorConfig" :editor="ClassicEditor"/>
|
3
|
+
</template>
|
4
|
+
|
5
|
+
<script>
|
6
|
+
import "./index.css";
|
7
|
+
import {Ckeditor} from "@ckeditor/ckeditor5-vue";
|
8
|
+
import {computed} from "vue";
|
9
|
+
import {createScxUploadAdapterPlugin} from "./plugins/scx-upload-adapter.js";
|
10
|
+
import {ClassicEditor, InlineEditor} from "ckeditor5";
|
11
|
+
import "ckeditor5/ckeditor5.css";
|
12
|
+
import {defaultEditorConfig} from "./default-editor-config.js";
|
13
|
+
import {useScxFSS} from "scx-ui/scx/scx-fss";
|
14
|
+
|
15
|
+
export default {
|
16
|
+
name: "easy-ckeditor",
|
17
|
+
components: {
|
18
|
+
ckeditor: Ckeditor
|
19
|
+
},
|
20
|
+
props: {
|
21
|
+
modelValue: {
|
22
|
+
type: String,
|
23
|
+
default: "",
|
24
|
+
},
|
25
|
+
config: {}
|
26
|
+
},
|
27
|
+
setup(props, ctx) {
|
28
|
+
|
29
|
+
const fss = useScxFSS();
|
30
|
+
|
31
|
+
const scxUploadAdapterPlugin = createScxUploadAdapterPlugin(fss);
|
32
|
+
|
33
|
+
defaultEditorConfig.extraPlugins = [scxUploadAdapterPlugin];
|
34
|
+
|
35
|
+
const editorConfig = Object.assign(defaultEditorConfig, props.config);
|
36
|
+
|
37
|
+
const editorData = computed({
|
38
|
+
get() {
|
39
|
+
return props.modelValue;
|
40
|
+
},
|
41
|
+
set(value) {
|
42
|
+
ctx.emit("update:modelValue", value);
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
return {
|
47
|
+
ClassicEditor,
|
48
|
+
InlineEditor,
|
49
|
+
editorData,
|
50
|
+
editorConfig
|
51
|
+
};
|
52
|
+
}
|
53
|
+
};
|
54
|
+
</script>
|
55
|
+
|
56
|
+
<style>
|
57
|
+
|
58
|
+
</style>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class ScxUploadAdapter {
|
2
|
+
|
3
|
+
constructor(loader, fss) {
|
4
|
+
this.loader = loader;
|
5
|
+
this.fss = fss;
|
6
|
+
}
|
7
|
+
|
8
|
+
async upload() {
|
9
|
+
|
10
|
+
const needUploadFile = await this.loader.file;
|
11
|
+
|
12
|
+
const c = await this.fss.upload(needUploadFile, (type, v) => {
|
13
|
+
//这里为了使计算 md5 和 上传各占一半的进度所以这里做一点特殊的计算
|
14
|
+
if (type === "checking-md5") {
|
15
|
+
this.loader.uploadedPercent = v / 2;
|
16
|
+
} else if (type === "uploading") {
|
17
|
+
this.loader.uploadedPercent = 50 + v / 2;
|
18
|
+
}
|
19
|
+
});
|
20
|
+
|
21
|
+
this.loader.uploadedPercent = 100;
|
22
|
+
|
23
|
+
return {
|
24
|
+
default: this.fss.joinImageURL(c.item.fssObjectID),
|
25
|
+
};
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
function createScxUploadAdapterPlugin(fss) {
|
30
|
+
return function (editor) {
|
31
|
+
return editor.plugins.get("FileRepository").createUploadAdapter = function (loader) {
|
32
|
+
return new ScxUploadAdapter(loader, fss);
|
33
|
+
};
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
export {
|
38
|
+
createScxUploadAdapterPlugin,
|
39
|
+
};
|
@@ -0,0 +1,168 @@
|
|
1
|
+
<template>
|
2
|
+
<el-form-item :label="easyLabel" :prop="easyProp" :rules="easyRules">
|
3
|
+
<slot/>
|
4
|
+
</el-form-item>
|
5
|
+
</template>
|
6
|
+
|
7
|
+
<script>
|
8
|
+
import {computed} from "vue";
|
9
|
+
import {notBlank} from "@scx-js/scx-common";
|
10
|
+
import {checkIDCard, checkPhoneNumber, useCrudContext,} from "../../index.js";
|
11
|
+
|
12
|
+
export default {
|
13
|
+
name: "easy-form-item",
|
14
|
+
props: {
|
15
|
+
//是否使用标注在 easy-form-item 上的 model
|
16
|
+
//默认使用 el-form 上的
|
17
|
+
useModel: {
|
18
|
+
type: Boolean,
|
19
|
+
default: false
|
20
|
+
},
|
21
|
+
//若代校验数据不属于 el-form :model 中的数据
|
22
|
+
//则可以直接赋值给 model
|
23
|
+
model: {
|
24
|
+
type: [String, Number, Array, Object],
|
25
|
+
default: null
|
26
|
+
},
|
27
|
+
required: {
|
28
|
+
type: Boolean,
|
29
|
+
default: false
|
30
|
+
},
|
31
|
+
trigger: {
|
32
|
+
type: String,
|
33
|
+
default: "blur"
|
34
|
+
},
|
35
|
+
label: {
|
36
|
+
type: String,
|
37
|
+
default: null
|
38
|
+
},
|
39
|
+
prop: {
|
40
|
+
type: String,
|
41
|
+
required: false,
|
42
|
+
default: null
|
43
|
+
},
|
44
|
+
unique: {
|
45
|
+
type: Boolean,
|
46
|
+
default: false
|
47
|
+
},
|
48
|
+
checkIDCard: {
|
49
|
+
type: Boolean,
|
50
|
+
default: false
|
51
|
+
},
|
52
|
+
checkPhoneNumber: {
|
53
|
+
type: Boolean,
|
54
|
+
default: false
|
55
|
+
},
|
56
|
+
validator: {
|
57
|
+
default: null
|
58
|
+
}
|
59
|
+
},
|
60
|
+
setup(props, context) {
|
61
|
+
|
62
|
+
const crudContext = useCrudContext();
|
63
|
+
|
64
|
+
const easyProp = computed(() => props.prop ? props.prop : getUUID());
|
65
|
+
|
66
|
+
const easyLabel = computed(() => {
|
67
|
+
if (props.label) {
|
68
|
+
const l = props.label.trim();
|
69
|
+
return l.endsWith(":") ? l : l + " :";
|
70
|
+
} else {
|
71
|
+
return props.label;
|
72
|
+
}
|
73
|
+
});
|
74
|
+
|
75
|
+
const fieldLabel = computed(() => props.label ? props.label : props.prop);
|
76
|
+
|
77
|
+
/**
|
78
|
+
* 获取校验值
|
79
|
+
*/
|
80
|
+
function getFinalValue(v) {
|
81
|
+
return props.useModel ? props.model : v;
|
82
|
+
}
|
83
|
+
|
84
|
+
function getRequiredRule() {
|
85
|
+
return {
|
86
|
+
validator: (a, b, callback) => {
|
87
|
+
if (notBlank(getFinalValue(b))) {
|
88
|
+
callback();
|
89
|
+
} else {
|
90
|
+
callback(new Error());
|
91
|
+
}
|
92
|
+
},
|
93
|
+
required: true,
|
94
|
+
message: fieldLabel.value + "不能为空 !!!",
|
95
|
+
trigger: props.trigger
|
96
|
+
};
|
97
|
+
}
|
98
|
+
|
99
|
+
function getUniqueRule() {
|
100
|
+
return {
|
101
|
+
validator: (a, b, c) => crudContext.checkUnique(a, getFinalValue(b), c, fieldLabel.value),
|
102
|
+
required: false,
|
103
|
+
trigger: props.trigger
|
104
|
+
};
|
105
|
+
}
|
106
|
+
|
107
|
+
function getCheckPhoneNumberRule() {
|
108
|
+
return {
|
109
|
+
validator: (a, b, c) => checkPhoneNumber(a, getFinalValue(b), c, fieldLabel.value),
|
110
|
+
required: false,
|
111
|
+
trigger: props.trigger
|
112
|
+
};
|
113
|
+
}
|
114
|
+
|
115
|
+
function getCheckIDCardRule() {
|
116
|
+
return {
|
117
|
+
validator: (a, b, c) => checkIDCard(a, getFinalValue(b), c, fieldLabel.value),
|
118
|
+
required: false,
|
119
|
+
trigger: props.trigger
|
120
|
+
};
|
121
|
+
}
|
122
|
+
|
123
|
+
function getValidatorRule() {
|
124
|
+
const vList = Array.isArray(props.validator) ? props.validator : [props.validator];
|
125
|
+
return vList.filter(v => v instanceof Function).map(v => {
|
126
|
+
return {
|
127
|
+
validator: (a, b, c) => v(a, getFinalValue(b), c, fieldLabel.value),
|
128
|
+
trigger: props.trigger
|
129
|
+
};
|
130
|
+
});
|
131
|
+
}
|
132
|
+
|
133
|
+
const easyRules = computed(() => {
|
134
|
+
const tempRules = [];
|
135
|
+
if (props.required) {
|
136
|
+
tempRules.push(getRequiredRule());
|
137
|
+
}
|
138
|
+
if (props.unique) {
|
139
|
+
if (crudContext == null) {
|
140
|
+
console.error("未找到能够注入的 crudContext 对象, 无法实现 unique");
|
141
|
+
} else {
|
142
|
+
tempRules.push(getUniqueRule());
|
143
|
+
}
|
144
|
+
}
|
145
|
+
if (props.checkPhoneNumber) {
|
146
|
+
tempRules.push(getCheckPhoneNumberRule());
|
147
|
+
}
|
148
|
+
if (props.checkIDCard) {
|
149
|
+
tempRules.push(getCheckIDCardRule());
|
150
|
+
}
|
151
|
+
if (props.validator) {
|
152
|
+
tempRules.push(...getValidatorRule());
|
153
|
+
}
|
154
|
+
return tempRules;
|
155
|
+
});
|
156
|
+
|
157
|
+
return {
|
158
|
+
easyProp,
|
159
|
+
easyLabel,
|
160
|
+
easyRules
|
161
|
+
};
|
162
|
+
}
|
163
|
+
};
|
164
|
+
</script>
|
165
|
+
|
166
|
+
<style scoped>
|
167
|
+
|
168
|
+
</style>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
.easy-image-preview {
|
2
|
+
width: 100px;
|
3
|
+
height: 100px;
|
4
|
+
border-radius: 6px;
|
5
|
+
border: 3px dashed rgba(114, 114, 114, 0.5);
|
6
|
+
/* 修复element 默认 el-image 中 display: inline-block 导致元素高度被撑开的问题 */
|
7
|
+
display: flex;
|
8
|
+
box-sizing: border-box;
|
9
|
+
}
|
10
|
+
|
11
|
+
.easy-image-no-preview {
|
12
|
+
width: 100px;
|
13
|
+
height: 100px;
|
14
|
+
display: flex;
|
15
|
+
background: var(--scx-overlay-bg);
|
16
|
+
color: var(--scx-text-placeholder-color);
|
17
|
+
border-radius: 6px;
|
18
|
+
justify-content: center;
|
19
|
+
align-items: center;
|
20
|
+
font-size: 20px;
|
21
|
+
font-weight: 600;
|
22
|
+
border: 3px dashed rgba(114, 114, 114, 0.5);
|
23
|
+
box-sizing: border-box;
|
24
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
<template>
|
2
|
+
<el-image v-if="listModelValue.length>0" :preview-src-list="previewSrcList"
|
3
|
+
:preview-teleported="true"
|
4
|
+
:src="src"
|
5
|
+
class="easy-image-preview"
|
6
|
+
style=""/>
|
7
|
+
<div v-else class="easy-image-no-preview">
|
8
|
+
无图片
|
9
|
+
</div>
|
10
|
+
</template>
|
11
|
+
|
12
|
+
<script>
|
13
|
+
import "./index.css";
|
14
|
+
import {computed} from "vue";
|
15
|
+
import {useAliOSS} from "../../index.js";
|
16
|
+
import {useScxFSS} from "@scx-js/scx-app-x";
|
17
|
+
|
18
|
+
|
19
|
+
export default {
|
20
|
+
name: "easy-image",
|
21
|
+
props: {
|
22
|
+
modelValue: {
|
23
|
+
type: [String, Array],
|
24
|
+
default: null
|
25
|
+
},
|
26
|
+
uploadHandlerType: {
|
27
|
+
type: String,
|
28
|
+
default: "scx-fss" // 取值 scx-fss ali-oss
|
29
|
+
},
|
30
|
+
},
|
31
|
+
setup(props) {
|
32
|
+
const scxFSS = useScxFSS();
|
33
|
+
|
34
|
+
const aliOSS = useAliOSS();
|
35
|
+
|
36
|
+
const listModelValue = computed(() => {
|
37
|
+
if (props.modelValue) {
|
38
|
+
return Array.isArray(props.modelValue) ? props.modelValue : [props.modelValue];
|
39
|
+
} else {
|
40
|
+
return [];
|
41
|
+
}
|
42
|
+
});
|
43
|
+
|
44
|
+
const previewSrcList = computed(() => {
|
45
|
+
switch (props.uploadHandlerType) {
|
46
|
+
case "scx-fss":
|
47
|
+
return listModelValue.value.map(d => scxFSS.joinImageURL(d));
|
48
|
+
case "ali-oss":
|
49
|
+
return listModelValue.value.map(d => aliOSS.joinURL(d));
|
50
|
+
default:
|
51
|
+
throw new Error("未知的 uploadHandlerType : " + props.uploadHandlerType);
|
52
|
+
}
|
53
|
+
});
|
54
|
+
|
55
|
+
const src = computed(() => {
|
56
|
+
const first = previewSrcList.value[0];
|
57
|
+
switch (props.uploadHandlerType) {
|
58
|
+
case "scx-fss":
|
59
|
+
return first + "?w=100&h=100";
|
60
|
+
case "ali-oss":
|
61
|
+
return first + "?x-oss-process=image/resize,w_100";
|
62
|
+
default:
|
63
|
+
throw new Error("未知的 uploadHandlerType : " + props.uploadHandlerType);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
|
67
|
+
return {
|
68
|
+
previewSrcList,
|
69
|
+
src,
|
70
|
+
listModelValue
|
71
|
+
};
|
72
|
+
|
73
|
+
}
|
74
|
+
};
|
75
|
+
</script>
|