@scx-js/scx-ui 0.0.1 → 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.
@@ -1,228 +1,228 @@
1
- <template>
2
- <div class="scx-upload-list">
3
-
4
- <!-- 隐藏的 input 用于触发点击上传事件 -->
5
- <input ref="hiddenInputRef" multiple placeholder="file" style="display: none" type="file"
6
- @change="onHiddenInputChange">
7
-
8
- <scx-group v-model="uploadInfoList"
9
- :before-remove="beforeRemove"
10
- :show-move-button="!disabled"
11
- :show-remove-button="!disabled">
12
- <template v-if="!disabled" #before>
13
- <!-- 上传按钮 -->
14
- <button class="upload-button" type="button" @click="selectFile">
15
- 点击上传, 当前共 {{ proxyModelValue.length }} 个文件
16
- </button>
17
- </template>
18
- <template #default="{index,item}">
19
- <slot :index="index" :item="item">
20
- <img :src="item.previewURL" alt="img" class="preview-image">
21
- <div class="preview-text">
22
- <a v-if="item.downloadURL" :href="item.downloadURL" class="file-name">{{ item.fileName }}</a>
23
- <span v-else class="file-name">{{ item.fileName }}</span>
24
- <div v-if="item.progressVisible" class="progress-state">
25
- <div class="progress-state-text">{{ item.progressState }}</div>
26
- <scx-progress v-model="item.progressValue"/>
27
- </div>
28
- <div v-else class="item-info">
29
- 上传时间 : {{ item.uploadTime }} 文件大小 : {{ item.fileSizeDisplay }}
30
- </div>
31
- </div>
32
- </slot>
33
- </template>
34
- </scx-group>
35
-
36
- </div>
37
- </template>
38
-
39
- <script>
40
- import "./index.css";
41
- import {computed, reactive, ref, watch} from "vue";
42
- import {arrayEquals, percentage} from "@scx-js/scx-common";
43
- import {ScxFSSHelper, UploadInfo} from "../scx-upload/helper.js";
44
- import {useScxFSS} from "@scx-js/scx-app-x";
45
- import ScxGroup from "../scx-group/index.vue";
46
- import ScxProgress from "../scx-progress/index.vue";
47
-
48
- export default {
49
- name: "scx-upload-list",
50
- components: {
51
- ScxGroup,
52
- ScxProgress
53
- },
54
- props: {
55
- modelValue: {
56
- type: Array,
57
- default: null
58
- },
59
- uploadHandler: {
60
- type: Function,
61
- default: null
62
- },
63
- fileInfoHandler: {
64
- type: Function,
65
- default: null
66
- },
67
- beforeUpload: {
68
- type: Function,
69
- default: null
70
- },
71
- onError: {
72
- type: Function,
73
- default: null
74
- },
75
- disabled: { //若为 true 则只具有展示效果 不能上传删除和排序
76
- type: Boolean,
77
- default: false
78
- },
79
- beforeDelete: {
80
- type: Function,
81
- default: null
82
- }
83
- },
84
- setup(props, ctx) {
85
- const scxFSS = useScxFSS();
86
- const scxFSSHelper = new ScxFSSHelper(scxFSS);
87
-
88
- function getFileInfoHandler() {
89
- return props.fileInfoHandler ? props.fileInfoHandler : (fileID) => scxFSSHelper.fileInfoHandler(fileID);
90
- }
91
-
92
- function getUploadHandler() {
93
- return props.uploadHandler ? props.uploadHandler : (needUploadFile, progress) => scxFSSHelper.uploadHandler(needUploadFile, progress);
94
- }
95
-
96
- function getOnError() {
97
- return props.onError ? props.onError : (error, file) => console.error(error, file);
98
- }
99
-
100
- const hiddenInputRef = ref(null);
101
-
102
- function selectFile() {
103
- hiddenInputRef.value.click();
104
- }
105
-
106
- function onHiddenInputChange(e) {
107
- const needUploadFiles = Array.from(e.target.files);
108
- //重置 上传 input 的值 保证即使点击重复文件也可以上传
109
- hiddenInputRef.value.value = null;
110
- callUploadHandler(needUploadFiles);
111
- }
112
-
113
- const proxyModelValue = computed({
114
- get() {
115
- //处理有时外部数据为 null 或 undefined 的情况
116
- return props.modelValue ? props.modelValue : [];
117
- },
118
- set(value) {
119
- ctx.emit("update:modelValue", value);
120
- }
121
- });
122
- /**
123
- * 已上传的信息列表
124
- * @type {Ref<UnwrapRef<UploadInfo[]>>}
125
- */
126
- const uploadInfoList = ref([]);
127
- /**
128
- * 当前是否有上传任务 防止多次点击上传文件按钮上传时产生多次上传任务
129
- * @type {boolean}
130
- */
131
- let hasUploadTask = false;
132
-
133
- //上传文件
134
- async function callUploadHandler(needUploadFiles) {
135
- if (props.beforeUpload) {
136
- const result = await props.beforeUpload(needUploadFiles);
137
- if (!result) {
138
- return;
139
- }
140
- }
141
- for (const needUploadFile of needUploadFiles) {
142
- const i = new UploadInfo();
143
- i.fileName = needUploadFile.name;
144
- i.file = needUploadFile;
145
- i.progressState = "等待中";
146
- i.progressVisible = true;
147
- i.progressValue = 0;
148
- i.previewURL = URL.createObjectURL(needUploadFile);
149
- uploadInfoList.value.push(i);
150
- }
151
- //如果当前没有上传任务 则进行递归上传
152
- if (!hasUploadTask) {
153
- await callUploadHandler0();
154
- }
155
- }
156
-
157
- /**
158
- * 这里我们为了减少服务器的压力并不采取批量上传 而是一条传完再传下一条
159
- * @returns {Promise<void>}
160
- */
161
- async function callUploadHandler0() {
162
- hasUploadTask = true;
163
- const nextNeedUpload = uploadInfoList.value.find(u => u.progressState === "等待中");
164
- if (nextNeedUpload) {
165
- const progress = (v, s = "上传中") => {
166
- //处理一下百分比的格式防止 33.33333333333339 这种情况出现
167
- nextNeedUpload.progressState = s;
168
- nextNeedUpload.progressValue = percentage(v, 100);
169
- };
170
- try {
171
- nextNeedUpload.fileID = await getUploadHandler()(nextNeedUpload.file, progress);
172
- nextNeedUpload.progressVisible = false;
173
- } catch (e) {
174
- getOnError()(e, nextNeedUpload.file);
175
- nextNeedUpload.progressState = "上传失败";
176
- }
177
- const item = await getFileInfoHandler()(nextNeedUpload.fileID);
178
- nextNeedUpload.fill(item);
179
- nextNeedUpload.file = null;
180
- nextNeedUpload.progressValue = 0;
181
- //进行下一次上传
182
- await callUploadHandler0();
183
- } else {
184
- hasUploadTask = false;
185
- }
186
- }
187
-
188
- function getFileIDs(l) {
189
- return l.map(d => d.fileID).filter(d => d);
190
- }
191
-
192
- function callFileInfoHandler(fileIDs) {
193
- if (!arrayEquals(fileIDs, getFileIDs(uploadInfoList.value))) {
194
- console.log("外部发生变化 !!!");
195
- uploadInfoList.value = fileIDs.map(fileID => {
196
- const u = reactive(new UploadInfo());
197
- u.fileID = fileID;
198
- u.fileName = fileID;
199
- getFileInfoHandler()(u.fileID).then(item => u.fill(item));
200
- return u;
201
- });
202
- }
203
- }
204
-
205
- //我们根据 proxyModelValue 实时更新 fileInfo
206
- watch(proxyModelValue, (newVal) => callFileInfoHandler(newVal), {immediate: true});
207
-
208
- function callProxyModelHandler(list) {
209
- const fileIDs = getFileIDs(list);
210
- if (!arrayEquals(fileIDs, proxyModelValue.value)) {
211
- console.log("内部发生变化 !!!");
212
- proxyModelValue.value = fileIDs;
213
- }
214
- }
215
-
216
- watch(uploadInfoList, (newVal) => callProxyModelHandler(newVal), {deep: true});
217
- const beforeRemove = props.beforeDelete ? (info) => props.beforeDelete(info.copy()) : null;
218
- return {
219
- hiddenInputRef,
220
- uploadInfoList,
221
- proxyModelValue,
222
- beforeRemove,
223
- onHiddenInputChange,
224
- selectFile,
225
- };
226
- }
227
- };
228
- </script>
1
+ <template>
2
+ <div class="scx-upload-list">
3
+
4
+ <!-- 隐藏的 input 用于触发点击上传事件 -->
5
+ <input ref="hiddenInputRef" multiple placeholder="file" style="display: none" type="file"
6
+ @change="onHiddenInputChange">
7
+
8
+ <scx-group v-model="uploadInfoList"
9
+ :before-remove="beforeRemove"
10
+ :show-move-button="!disabled"
11
+ :show-remove-button="!disabled">
12
+ <template v-if="!disabled" #before>
13
+ <!-- 上传按钮 -->
14
+ <button class="upload-button" type="button" @click="selectFile">
15
+ 点击上传, 当前共 {{ proxyModelValue.length }} 个文件
16
+ </button>
17
+ </template>
18
+ <template #default="{index,item}">
19
+ <slot :index="index" :item="item">
20
+ <img :src="item.previewURL" alt="img" class="preview-image">
21
+ <div class="preview-text">
22
+ <a v-if="item.downloadURL" :href="item.downloadURL" class="file-name">{{ item.fileName }}</a>
23
+ <span v-else class="file-name">{{ item.fileName }}</span>
24
+ <div v-if="item.progressVisible" class="progress-state">
25
+ <div class="progress-state-text">{{ item.progressState }}</div>
26
+ <scx-progress v-model="item.progressValue"/>
27
+ </div>
28
+ <div v-else class="item-info">
29
+ 上传时间 : {{ item.uploadTime }} 文件大小 : {{ item.fileSizeDisplay }}
30
+ </div>
31
+ </div>
32
+ </slot>
33
+ </template>
34
+ </scx-group>
35
+
36
+ </div>
37
+ </template>
38
+
39
+ <script>
40
+ import "./index.css";
41
+ import {computed, reactive, ref, watch} from "vue";
42
+ import {arrayEquals, percentage} from "@scx-js/scx-common";
43
+ import {ScxFSSHelper, UploadInfo} from "../scx-upload/helper.js";
44
+ import {useScxFSS} from "@scx-js/scx-app-x";
45
+ import ScxGroup from "../scx-group/index.vue";
46
+ import ScxProgress from "../scx-progress/index.vue";
47
+
48
+ export default {
49
+ name: "scx-upload-list",
50
+ components: {
51
+ ScxGroup,
52
+ ScxProgress
53
+ },
54
+ props: {
55
+ modelValue: {
56
+ type: Array,
57
+ default: null
58
+ },
59
+ uploadHandler: {
60
+ type: Function,
61
+ default: null
62
+ },
63
+ fileInfoHandler: {
64
+ type: Function,
65
+ default: null
66
+ },
67
+ beforeUpload: {
68
+ type: Function,
69
+ default: null
70
+ },
71
+ onError: {
72
+ type: Function,
73
+ default: null
74
+ },
75
+ disabled: { //若为 true 则只具有展示效果 不能上传删除和排序
76
+ type: Boolean,
77
+ default: false
78
+ },
79
+ beforeDelete: {
80
+ type: Function,
81
+ default: null
82
+ }
83
+ },
84
+ setup(props, ctx) {
85
+ const scxFSS = useScxFSS();
86
+ const scxFSSHelper = new ScxFSSHelper(scxFSS);
87
+
88
+ function getFileInfoHandler() {
89
+ return props.fileInfoHandler ? props.fileInfoHandler : (fileID) => scxFSSHelper.fileInfoHandler(fileID);
90
+ }
91
+
92
+ function getUploadHandler() {
93
+ return props.uploadHandler ? props.uploadHandler : (needUploadFile, progress) => scxFSSHelper.uploadHandler(needUploadFile, progress);
94
+ }
95
+
96
+ function getOnError() {
97
+ return props.onError ? props.onError : (error, file) => console.error(error, file);
98
+ }
99
+
100
+ const hiddenInputRef = ref(null);
101
+
102
+ function selectFile() {
103
+ hiddenInputRef.value.click();
104
+ }
105
+
106
+ function onHiddenInputChange(e) {
107
+ const needUploadFiles = Array.from(e.target.files);
108
+ //重置 上传 input 的值 保证即使点击重复文件也可以上传
109
+ hiddenInputRef.value.value = null;
110
+ callUploadHandler(needUploadFiles);
111
+ }
112
+
113
+ const proxyModelValue = computed({
114
+ get() {
115
+ //处理有时外部数据为 null 或 undefined 的情况
116
+ return props.modelValue ? props.modelValue : [];
117
+ },
118
+ set(value) {
119
+ ctx.emit("update:modelValue", value);
120
+ }
121
+ });
122
+ /**
123
+ * 已上传的信息列表
124
+ * @type {Ref<UnwrapRef<UploadInfo[]>>}
125
+ */
126
+ const uploadInfoList = ref([]);
127
+ /**
128
+ * 当前是否有上传任务 防止多次点击上传文件按钮上传时产生多次上传任务
129
+ * @type {boolean}
130
+ */
131
+ let hasUploadTask = false;
132
+
133
+ //上传文件
134
+ async function callUploadHandler(needUploadFiles) {
135
+ if (props.beforeUpload) {
136
+ const result = await props.beforeUpload(needUploadFiles);
137
+ if (!result) {
138
+ return;
139
+ }
140
+ }
141
+ for (const needUploadFile of needUploadFiles) {
142
+ const i = new UploadInfo();
143
+ i.fileName = needUploadFile.name;
144
+ i.file = needUploadFile;
145
+ i.progressState = "等待中";
146
+ i.progressVisible = true;
147
+ i.progressValue = 0;
148
+ i.previewURL = URL.createObjectURL(needUploadFile);
149
+ uploadInfoList.value.push(i);
150
+ }
151
+ //如果当前没有上传任务 则进行递归上传
152
+ if (!hasUploadTask) {
153
+ await callUploadHandler0();
154
+ }
155
+ }
156
+
157
+ /**
158
+ * 这里我们为了减少服务器的压力并不采取批量上传 而是一条传完再传下一条
159
+ * @returns {Promise<void>}
160
+ */
161
+ async function callUploadHandler0() {
162
+ hasUploadTask = true;
163
+ const nextNeedUpload = uploadInfoList.value.find(u => u.progressState === "等待中");
164
+ if (nextNeedUpload) {
165
+ const progress = (v, s = "上传中") => {
166
+ //处理一下百分比的格式防止 33.33333333333339 这种情况出现
167
+ nextNeedUpload.progressState = s;
168
+ nextNeedUpload.progressValue = percentage(v, 100);
169
+ };
170
+ try {
171
+ nextNeedUpload.fileID = await getUploadHandler()(nextNeedUpload.file, progress);
172
+ nextNeedUpload.progressVisible = false;
173
+ } catch (e) {
174
+ getOnError()(e, nextNeedUpload.file);
175
+ nextNeedUpload.progressState = "上传失败";
176
+ }
177
+ const item = await getFileInfoHandler()(nextNeedUpload.fileID);
178
+ nextNeedUpload.fill(item);
179
+ nextNeedUpload.file = null;
180
+ nextNeedUpload.progressValue = 0;
181
+ //进行下一次上传
182
+ await callUploadHandler0();
183
+ } else {
184
+ hasUploadTask = false;
185
+ }
186
+ }
187
+
188
+ function getFileIDs(l) {
189
+ return l.map(d => d.fileID).filter(d => d);
190
+ }
191
+
192
+ function callFileInfoHandler(fileIDs) {
193
+ if (!arrayEquals(fileIDs, getFileIDs(uploadInfoList.value))) {
194
+ console.log("外部发生变化 !!!");
195
+ uploadInfoList.value = fileIDs.map(fileID => {
196
+ const u = reactive(new UploadInfo());
197
+ u.fileID = fileID;
198
+ u.fileName = fileID;
199
+ getFileInfoHandler()(u.fileID).then(item => u.fill(item));
200
+ return u;
201
+ });
202
+ }
203
+ }
204
+
205
+ //我们根据 proxyModelValue 实时更新 fileInfo
206
+ watch(proxyModelValue, (newVal) => callFileInfoHandler(newVal), {immediate: true});
207
+
208
+ function callProxyModelHandler(list) {
209
+ const fileIDs = getFileIDs(list);
210
+ if (!arrayEquals(fileIDs, proxyModelValue.value)) {
211
+ console.log("内部发生变化 !!!");
212
+ proxyModelValue.value = fileIDs;
213
+ }
214
+ }
215
+
216
+ watch(uploadInfoList, (newVal) => callProxyModelHandler(newVal), {deep: true});
217
+ const beforeRemove = props.beforeDelete ? (info) => props.beforeDelete(info.copy()) : null;
218
+ return {
219
+ hiddenInputRef,
220
+ uploadInfoList,
221
+ proxyModelValue,
222
+ beforeRemove,
223
+ onHiddenInputChange,
224
+ selectFile,
225
+ };
226
+ }
227
+ };
228
+ </script>
@@ -1,13 +1,13 @@
1
- /**
2
- * 修改主题
3
- * @param value {boolean} 传入 true 或 false
4
- */
5
- function changeTheme(value) {
6
- if (value) {
7
- document.documentElement.classList.add("dark");
8
- } else {
9
- document.documentElement.classList.remove("dark");
10
- }
11
- }
12
-
13
- export {changeTheme};
1
+ /**
2
+ * 修改主题
3
+ * @param value {boolean} 传入 true 或 false
4
+ */
5
+ function changeTheme(value) {
6
+ if (value) {
7
+ document.documentElement.classList.add("dark");
8
+ } else {
9
+ document.documentElement.classList.remove("dark");
10
+ }
11
+ }
12
+
13
+ export {changeTheme};
package/style/dark.css CHANGED
@@ -1,59 +1,59 @@
1
- /* 此处重写项目中最基础的 css 变量 */
2
- html.dark {
3
-
4
- /* 主要强调色 */
5
- --scx-theme: rgb(72, 147, 73);
6
- /* 用于背景强调色 或 hover 背景色 */
7
- --scx-theme-bg: rgb(0, 71, 25, 0.2);
8
- /* 次要强调色 */
9
- --scx-theme-secondary: rgba(72, 147, 73, 0.5);
10
- /* 主要背景 (也可以为图片) */
11
- --scx-bg: #2b2b2b;
12
- /* 主要文字颜色 */
13
- --scx-text-color: whitesmoke;
14
- /* 次要文字颜色 */
15
- --scx-text-secondary-color: #909399;
16
- /* 占位文字颜色 */
17
- --scx-text-placeholder-color: #a8abb2;
18
-
19
- /* 滚动条背景 */
20
- --scx-scrollbar-bg: rgb(20, 20, 20);
21
- /* 滚动条拖动滑块背景 */
22
- --scx-scrollbar-thumb-bg: rgba(72, 147, 73, 0.4);
23
- /* 滚动条拖动滑块背景 (hover) */
24
- --scx-scrollbar-thumb-hover-bg: rgba(72, 147, 73, 0.8);
25
-
26
- /* 强调内容背景 */
27
- --scx-overlay-bg: #3c3c3c;
28
-
29
- /* 磨砂玻璃背景 */
30
- --scx-glass-bg: rgba(50, 50, 50, 0.8);
31
- /* 背景滤镜 */
32
- --scx-glass-bg-filter: blur(8px);
33
-
34
- /* 通用的阴影 分别是 [颜色, X 偏移量, Y 偏移量, 模糊, 扩张] */
35
- --scx-box-shadow: rgba(0, 0, 0, 0.4) 1px 1px 3px 0px;
36
- /* 没有偏移量的阴影 */
37
- --scx-box-shadow-center: rgba(0, 0, 0, 0.4) 0 0 3px 1px;
38
- /* 只需要上方有阴影 */
39
- --scx-box-shadow-top: rgba(0, 0, 0, 0.4) 0 -1px 3px 0px;
40
- /* 只需要左边有阴影 */
41
- --scx-box-shadow-left: rgba(0, 0, 0, 0.4) -1px 0 3px 0px;
42
- /* 只需要下方有阴影 */
43
- --scx-box-shadow-bottom: rgba(0, 0, 0, 0.4) 0 1px 3px 0px;
44
- /* 只需要右边有阴影 */
45
- --scx-box-shadow-right: rgba(0, 0, 0, 0.4) 1px 0 3px 0px;
46
-
47
- /* 输入框 */
48
- --scx-input_bg: rgba(255, 255, 255, 0.2);
49
- --scx-input_box-shadow: rgba(180, 180, 180, 0.6) 0 0 1px 1px;
50
- --scx-input-hover_box-shadow: rgba(44, 170, 46, 0.6) 0 0 2px 2px;
51
-
52
- /* scx-panel 组件 */
53
- --scx-panel-item_bg: rgba(255, 255, 255, 0.2);
54
- --scx-panel-item_border-color: transparent;
55
- --scx-panel-item_hover-bg: rgb(72, 147, 73);
56
- --scx-panel-item_hover-border-color: transparent;
57
- --scx-panel-item_hover-color: whitesmoke;
58
-
59
- }
1
+ /* 此处重写项目中最基础的 css 变量 */
2
+ html.dark {
3
+
4
+ /* 主要强调色 */
5
+ --scx-theme: rgb(72, 147, 73);
6
+ /* 用于背景强调色 或 hover 背景色 */
7
+ --scx-theme-bg: rgb(0, 71, 25, 0.2);
8
+ /* 次要强调色 */
9
+ --scx-theme-secondary: rgba(72, 147, 73, 0.5);
10
+ /* 主要背景 (也可以为图片) */
11
+ --scx-bg: #2b2b2b;
12
+ /* 主要文字颜色 */
13
+ --scx-text-color: whitesmoke;
14
+ /* 次要文字颜色 */
15
+ --scx-text-secondary-color: #909399;
16
+ /* 占位文字颜色 */
17
+ --scx-text-placeholder-color: #a8abb2;
18
+
19
+ /* 滚动条背景 */
20
+ --scx-scrollbar-bg: rgb(20, 20, 20);
21
+ /* 滚动条拖动滑块背景 */
22
+ --scx-scrollbar-thumb-bg: rgba(72, 147, 73, 0.4);
23
+ /* 滚动条拖动滑块背景 (hover) */
24
+ --scx-scrollbar-thumb-hover-bg: rgba(72, 147, 73, 0.8);
25
+
26
+ /* 强调内容背景 */
27
+ --scx-overlay-bg: #3c3c3c;
28
+
29
+ /* 磨砂玻璃背景 */
30
+ --scx-glass-bg: rgba(50, 50, 50, 0.8);
31
+ /* 背景滤镜 */
32
+ --scx-glass-bg-filter: blur(8px);
33
+
34
+ /* 通用的阴影 分别是 [颜色, X 偏移量, Y 偏移量, 模糊, 扩张] */
35
+ --scx-box-shadow: rgba(0, 0, 0, 0.4) 1px 1px 3px 0px;
36
+ /* 没有偏移量的阴影 */
37
+ --scx-box-shadow-center: rgba(0, 0, 0, 0.4) 0 0 3px 1px;
38
+ /* 只需要上方有阴影 */
39
+ --scx-box-shadow-top: rgba(0, 0, 0, 0.4) 0 -1px 3px 0px;
40
+ /* 只需要左边有阴影 */
41
+ --scx-box-shadow-left: rgba(0, 0, 0, 0.4) -1px 0 3px 0px;
42
+ /* 只需要下方有阴影 */
43
+ --scx-box-shadow-bottom: rgba(0, 0, 0, 0.4) 0 1px 3px 0px;
44
+ /* 只需要右边有阴影 */
45
+ --scx-box-shadow-right: rgba(0, 0, 0, 0.4) 1px 0 3px 0px;
46
+
47
+ /* 输入框 */
48
+ --scx-input_bg: rgba(255, 255, 255, 0.2);
49
+ --scx-input_box-shadow: rgba(180, 180, 180, 0.6) 0 0 1px 1px;
50
+ --scx-input-hover_box-shadow: rgba(44, 170, 46, 0.6) 0 0 2px 2px;
51
+
52
+ /* scx-panel 组件 */
53
+ --scx-panel-item_bg: rgba(255, 255, 255, 0.2);
54
+ --scx-panel-item_border-color: transparent;
55
+ --scx-panel-item_hover-bg: rgb(72, 147, 73);
56
+ --scx-panel-item_hover-border-color: transparent;
57
+ --scx-panel-item_hover-color: whitesmoke;
58
+
59
+ }