@sugarat/easypicker2-client 2.4.1

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.
Files changed (145) hide show
  1. package/.env +6 -0
  2. package/.env.production +3 -0
  3. package/.env.test +4 -0
  4. package/.eslintignore +0 -0
  5. package/.eslintrc.json +57 -0
  6. package/.github/workflows/main.yml +61 -0
  7. package/.prettierrc.js +9 -0
  8. package/LICENSE +21 -0
  9. package/README.md +86 -0
  10. package/auto-imports.d.ts +6 -0
  11. package/components.d.ts +56 -0
  12. package/docker/ep_backup/easypicker2.sql +214 -0
  13. package/docker/ep_backup/mongodb/easypicker2/action.bson +0 -0
  14. package/docker/ep_backup/mongodb/easypicker2/action.metadata.json +1 -0
  15. package/docker/ep_backup/mongodb/easypicker2/log.bson +0 -0
  16. package/docker/ep_backup/mongodb/easypicker2/log.metadata.json +1 -0
  17. package/docker/ep_backup/user-config.json +176 -0
  18. package/docs/.env +1 -0
  19. package/docs/.env.production +2 -0
  20. package/docs/.vitepress/config.ts +204 -0
  21. package/docs/.vitepress/theme/bg.png +0 -0
  22. package/docs/.vitepress/theme/index.scss +41 -0
  23. package/docs/.vitepress/theme/index.ts +5 -0
  24. package/docs/author.md +24 -0
  25. package/docs/auto-imports.d.ts +6 -0
  26. package/docs/components.d.ts +17 -0
  27. package/docs/deploy/design/api.md +3 -0
  28. package/docs/deploy/design/db.md +3 -0
  29. package/docs/deploy/design/index.md +3 -0
  30. package/docs/deploy/design/shell.md +9 -0
  31. package/docs/deploy/faq.md +86 -0
  32. package/docs/deploy/index.md +9 -0
  33. package/docs/deploy/local.md +275 -0
  34. package/docs/deploy/online-new.md +610 -0
  35. package/docs/deploy/online.md +683 -0
  36. package/docs/deploy/qiniu.md +183 -0
  37. package/docs/index.md +40 -0
  38. package/docs/introduction/about/code.md +26 -0
  39. package/docs/introduction/about/index.md +33 -0
  40. package/docs/introduction/feature/index.md +3 -0
  41. package/docs/plan/log.md +333 -0
  42. package/docs/plan/todo.md +127 -0
  43. package/docs/plan/wish.md +29 -0
  44. package/docs/praise/index.md +45 -0
  45. package/docs/public/favicon.ico +0 -0
  46. package/docs/public/logo.png +0 -0
  47. package/docs/public/robots.txt +2 -0
  48. package/docs/src/apis/ajax.ts +66 -0
  49. package/docs/src/apis/index.ts +1 -0
  50. package/docs/src/apis/modules/wish.ts +20 -0
  51. package/docs/src/components/Avatar.vue +60 -0
  52. package/docs/src/components/Home.vue +85 -0
  53. package/docs/src/components/Picture.vue +13 -0
  54. package/docs/src/components/Praise.vue +52 -0
  55. package/docs/src/components/WishBtn.vue +98 -0
  56. package/docs/src/components/WishPanel.vue +170 -0
  57. package/docs/src/components/callme/index.vue +72 -0
  58. package/docs/vite.config.ts +42 -0
  59. package/index.html +127 -0
  60. package/package.json +52 -0
  61. package/public/favicon.ico +0 -0
  62. package/public/logo.png +0 -0
  63. package/scripts/deploy/docs.mjs +24 -0
  64. package/scripts/deploy/prod.mjs +24 -0
  65. package/scripts/deploy/test.mjs +26 -0
  66. package/src/@types/ajax.d.ts +5 -0
  67. package/src/@types/api.d.ts +305 -0
  68. package/src/@types/lib.d.ts +26 -0
  69. package/src/@types/page.d.ts +18 -0
  70. package/src/App.vue +36 -0
  71. package/src/apis/ajax.ts +70 -0
  72. package/src/apis/index.ts +20 -0
  73. package/src/apis/modules/action.ts +17 -0
  74. package/src/apis/modules/category.ts +20 -0
  75. package/src/apis/modules/config.ts +19 -0
  76. package/src/apis/modules/file.ts +150 -0
  77. package/src/apis/modules/people.ts +81 -0
  78. package/src/apis/modules/public.ts +49 -0
  79. package/src/apis/modules/super/overview.ts +56 -0
  80. package/src/apis/modules/super/user.ts +62 -0
  81. package/src/apis/modules/task.ts +67 -0
  82. package/src/apis/modules/user.ts +56 -0
  83. package/src/apis/modules/wish.ts +31 -0
  84. package/src/assets/i/EasyPicker.png +0 -0
  85. package/src/assets/logo.png +0 -0
  86. package/src/assets/styles/app.css +69 -0
  87. package/src/components/HomeFooter/index.vue +134 -0
  88. package/src/components/HomeHeader/index.vue +156 -0
  89. package/src/components/InfosForm/index.vue +73 -0
  90. package/src/components/MessageList/index.vue +155 -0
  91. package/src/components/MessagePanel/index.vue +42 -0
  92. package/src/components/Praise/index.vue +102 -0
  93. package/src/components/QrCode.vue +44 -0
  94. package/src/components/linkDialog.vue +104 -0
  95. package/src/components/loginPanel.vue +92 -0
  96. package/src/constants/index.ts +83 -0
  97. package/src/env.d.ts +8 -0
  98. package/src/main.ts +19 -0
  99. package/src/pages/404/index.vue +59 -0
  100. package/src/pages/about/index.vue +152 -0
  101. package/src/pages/callme/index.vue +155 -0
  102. package/src/pages/dashboard/config/index.vue +264 -0
  103. package/src/pages/dashboard/files/index.vue +1152 -0
  104. package/src/pages/dashboard/index.vue +335 -0
  105. package/src/pages/dashboard/manage/config/index.vue +97 -0
  106. package/src/pages/dashboard/manage/index.vue +105 -0
  107. package/src/pages/dashboard/manage/overview/index.vue +488 -0
  108. package/src/pages/dashboard/manage/user/index.vue +679 -0
  109. package/src/pages/dashboard/manage/wish/index.vue +257 -0
  110. package/src/pages/dashboard/tasks/components/CategoryPanel.vue +208 -0
  111. package/src/pages/dashboard/tasks/components/CreateTask.vue +93 -0
  112. package/src/pages/dashboard/tasks/components/TaskInfo.vue +129 -0
  113. package/src/pages/dashboard/tasks/components/infoPanel/ddl.vue +96 -0
  114. package/src/pages/dashboard/tasks/components/infoPanel/file.vue +175 -0
  115. package/src/pages/dashboard/tasks/components/infoPanel/info.vue +477 -0
  116. package/src/pages/dashboard/tasks/components/infoPanel/people.vue +567 -0
  117. package/src/pages/dashboard/tasks/components/infoPanel/template.vue +146 -0
  118. package/src/pages/dashboard/tasks/components/infoPanel/tip.vue +55 -0
  119. package/src/pages/dashboard/tasks/components/infoPanel/tipInfo.vue +196 -0
  120. package/src/pages/dashboard/tasks/index.vue +302 -0
  121. package/src/pages/dashboard/tasks/public.ts +32 -0
  122. package/src/pages/disabled/index.vue +47 -0
  123. package/src/pages/feedback/index.vue +5 -0
  124. package/src/pages/home/index.vue +72 -0
  125. package/src/pages/login/index.vue +270 -0
  126. package/src/pages/register/index.vue +211 -0
  127. package/src/pages/reset/index.vue +186 -0
  128. package/src/pages/task/index.vue +897 -0
  129. package/src/pages/wish/index.vue +152 -0
  130. package/src/router/Interceptor/index.ts +112 -0
  131. package/src/router/index.ts +13 -0
  132. package/src/router/routes/index.ts +197 -0
  133. package/src/shims-vue.d.ts +6 -0
  134. package/src/store/index.ts +17 -0
  135. package/src/store/modules/category.ts +44 -0
  136. package/src/store/modules/public.ts +27 -0
  137. package/src/store/modules/task.ts +55 -0
  138. package/src/store/modules/user.ts +57 -0
  139. package/src/utils/elementUI.ts +8 -0
  140. package/src/utils/networkUtil.ts +236 -0
  141. package/src/utils/other.ts +25 -0
  142. package/src/utils/regExp.ts +11 -0
  143. package/src/utils/stringUtil.ts +242 -0
  144. package/tsconfig.json +24 -0
  145. package/vite.config.ts +55 -0
@@ -0,0 +1,477 @@
1
+ <template>
2
+ <div class="tc">
3
+ <tip
4
+ :imgs="[
5
+ 'https://img.cdn.sugarat.top/mdImg/MTY1MDE4MzM3NjUyNg==650183376526',
6
+ 'https://img.cdn.sugarat.top/mdImg/MTY1MTQ5NjU2ODcyNg==651496568726'
7
+ ]"
8
+ >上传文件必填表单信息</tip
9
+ >
10
+ <div class="auto-format">
11
+ <span>文件自动重命名:</span>
12
+ <el-switch
13
+ style="display: block"
14
+ v-model="autoRewrite"
15
+ active-color="#13ce66"
16
+ inactive-color="#ff4949"
17
+ active-text="开"
18
+ @change="handleChange"
19
+ inactive-text="关"
20
+ ></el-switch>
21
+ </div>
22
+ <div v-if="autoRewrite" style="margin-bottom: 10px">
23
+ 预期格式:
24
+ <span style="color: #409eff">{{ resFormat }}</span>
25
+ </div>
26
+ <div v-if="autoRewrite" style="margin-bottom: 10px">
27
+ 分割符:
28
+ <el-select
29
+ @change="handleChangeSplitChar"
30
+ v-model="formatData.splitChar"
31
+ placeholder="分隔符"
32
+ style="width: 60px"
33
+ size="small"
34
+ >
35
+ <el-option v-for="v in splitCharList" :key="v" :label="v" :value="v" />
36
+ </el-select>
37
+ </div>
38
+ <tip v-if="autoRewrite" style="color: red"
39
+ >开启自动重命名后,重点关注文件名格式是否符合预期</tip
40
+ >
41
+ <div>
42
+ 预览
43
+ <el-switch
44
+ v-model="openPreview"
45
+ inline-prompt
46
+ active-text="是"
47
+ inactive-text="否"
48
+ active-color="#13ce66"
49
+ inactive-color="#ff4949"
50
+ />
51
+ </div>
52
+ <!-- 必填信息区域 -->
53
+ <div class="form-wrapper">
54
+ <InfosForm v-if="openPreview" :infos="infos" :disabled="openPreview" />
55
+ <el-form v-else label-width="100px">
56
+ <el-form-item v-for="(item, idx) in infos" :key="idx">
57
+ <template #label>
58
+ <div class="flex fc fac">
59
+ <div class="num-wrapper">
60
+ <div>{{ idx + 1 }}</div>
61
+ </div>
62
+ <div class="form-item-type" :class="item.type">
63
+ {{ getTypeDes(item.type) }}
64
+ </div>
65
+ </div>
66
+ </template>
67
+ <el-input
68
+ placeholder="输入内容"
69
+ v-model="item.text"
70
+ :maxlength="maxInputLength"
71
+ clearable
72
+ show-word-limit
73
+ >
74
+ <template #append>
75
+ <div class="form-item-wrapper">
76
+ <el-icon
77
+ :color="infos.length > 1 ? 'red' : 'grey'"
78
+ @click="deleteInfo(idx)"
79
+ >
80
+ <CircleCloseFilled />
81
+ </el-icon>
82
+ <el-icon
83
+ color="#000"
84
+ style="margin-left: 6px"
85
+ v-if="idx > 0"
86
+ @click="moveInfoUp(idx)"
87
+ >
88
+ <Top />
89
+ </el-icon>
90
+ </div>
91
+ </template>
92
+ </el-input>
93
+ <div
94
+ v-if="item.type === 'radio' || item.type === 'select'"
95
+ class="radio-list"
96
+ >
97
+ <el-input
98
+ size="small"
99
+ v-for="(v, idx) in item.children"
100
+ :key="idx"
101
+ placeholder="输入内容"
102
+ v-model="v.text"
103
+ :maxlength="maxInputLength"
104
+ clearable
105
+ show-word-limit
106
+ >
107
+ <template #append>
108
+ <div class="form-item-wrapper">
109
+ <el-icon
110
+ :color="item.children.length > 2 ? 'red' : 'grey'"
111
+ @click="deleteInfo(idx, item.children, 2)"
112
+ >
113
+ <CircleCloseFilled />
114
+ </el-icon>
115
+ <template v-if="idx + 1 === item.children.length">
116
+ <el-icon
117
+ style="margin-left: 10px"
118
+ color="#67C23A"
119
+ @click="addInfo(item.children, item.type)"
120
+ >
121
+ <CirclePlusFilled />
122
+ </el-icon>
123
+ </template>
124
+ </div>
125
+ </template>
126
+ </el-input>
127
+ </div>
128
+ </el-form-item>
129
+ </el-form>
130
+ </div>
131
+ <div class="p10" v-if="showAddInfo">
132
+ <el-button
133
+ size="small"
134
+ type="primary"
135
+ @click="
136
+ () => {
137
+ addInfo()
138
+ }
139
+ "
140
+ round
141
+ >添加一项</el-button
142
+ >
143
+ <el-select
144
+ style="margin: 0 10px"
145
+ size="small"
146
+ v-model="selectType"
147
+ placeholder="选择添加的类型"
148
+ >
149
+ <el-option
150
+ v-for="(v, idx) in infoTypeList"
151
+ :key="idx"
152
+ :label="v.label"
153
+ :value="v.value"
154
+ />
155
+ </el-select>
156
+ <el-button type="primary" text @click="showHelp">提示❓</el-button>
157
+ </div>
158
+ <!-- 从其它任务导入 -->
159
+ <el-button size="small" type="warning" @click="openImportPanel"
160
+ >从其它任务导入</el-button
161
+ >
162
+ <div class="p10">
163
+ <tip>支持从已有的任务直接导入表单信息</tip>
164
+ <el-button type="success" @click="saveInfo" style="width: 200px"
165
+ >保存</el-button
166
+ >
167
+ </div>
168
+ <div style="color: red" v-if="needSave">有变动,请记得点击保存</div>
169
+ <div class="info-panel">
170
+ <el-dialog
171
+ :fullscreen="isMobile"
172
+ title="表单信息导入"
173
+ v-model="showImportPanel"
174
+ >
175
+ <el-form
176
+ :model="importPanelInfo"
177
+ label-width="100px"
178
+ label-position="right"
179
+ >
180
+ <el-form-item label="任务">
181
+ <el-select
182
+ filterable
183
+ v-model="importPanelInfo.taskValue"
184
+ placeholder="请选择"
185
+ no-data-text="无可用任务"
186
+ >
187
+ <el-option
188
+ v-for="t in importPanelInfo.taskList"
189
+ :key="t.taskKey"
190
+ :label="t.name"
191
+ :value="t.taskKey"
192
+ >
193
+ </el-option>
194
+ </el-select>
195
+ </el-form-item>
196
+ <tip>{{ importPanelInfo.taskValue ? '' : '无可用任务' }}</tip>
197
+ </el-form>
198
+ <template #footer>
199
+ <span class="dialog-footer">
200
+ <el-button @click="showImportPanel = false">取 消</el-button>
201
+ <el-button
202
+ :disabled="!importPanelInfo.taskValue"
203
+ type="primary"
204
+ @click="handleSaveImportInfo"
205
+ >确 定
206
+ </el-button>
207
+ </span>
208
+ </template>
209
+ </el-dialog>
210
+ </div>
211
+ </div>
212
+ </template>
213
+ <script lang="ts" setup>
214
+ import { ElMessage, ElMessageBox } from 'element-plus'
215
+ import { computed, reactive, ref, watch, watchEffect } from 'vue'
216
+ import {
217
+ CircleCloseFilled,
218
+ CirclePlusFilled,
219
+ Top
220
+ } from '@element-plus/icons-vue'
221
+ import { useStore } from 'vuex'
222
+ import { updateTaskInfo } from '../../public'
223
+ import Tip from './tip.vue'
224
+ import { TaskApi } from '@/apis'
225
+ import InfosForm from '@/components/InfosForm/index.vue'
226
+ import {
227
+ getDefaultFormat,
228
+ parseFileFormat,
229
+ parseInfo
230
+ } from '@/utils/stringUtil'
231
+
232
+ const props = defineProps({
233
+ rewrite: {
234
+ type: Number,
235
+ default: 0
236
+ },
237
+ info: {
238
+ typs: String,
239
+ default: '[]'
240
+ },
241
+ k: {
242
+ type: String,
243
+ default: ''
244
+ },
245
+ format: {
246
+ type: String,
247
+ default: '',
248
+ required: false
249
+ }
250
+ })
251
+ const formatData = reactive(getDefaultFormat())
252
+ const openPreview = ref(false)
253
+ const infoTypeList = reactive<{ label: string; value: InfoItemType }[]>([
254
+ {
255
+ label: '输入框',
256
+ value: 'input'
257
+ },
258
+ {
259
+ label: '固定内容',
260
+ value: 'text'
261
+ },
262
+ {
263
+ label: '单选框',
264
+ value: 'radio'
265
+ },
266
+ {
267
+ label: '下拉选择',
268
+ value: 'select'
269
+ }
270
+ ])
271
+ const getTypeDes = (type: string) =>
272
+ infoTypeList.find((v) => v.value === type)?.label
273
+
274
+ const selectType = ref<InfoItemType>('input')
275
+
276
+ const maxInputLength = +import.meta.env.VITE_APP_INPUT_MAX_LENGTH || 10
277
+
278
+ const autoRewrite = ref(false)
279
+ const infos = reactive<InfoItem[]>([])
280
+ const needSave = ref(false)
281
+ // TODO:暂时限制表单的题目数为10,遇到case再修改
282
+ const showAddInfo = computed(() => infos.length < 10 && !openPreview.value)
283
+ // 负责清空
284
+ watch(
285
+ () => props.info,
286
+ () => {
287
+ infos.splice(0, infos.length)
288
+ selectType.value = 'input'
289
+ openPreview.value = false
290
+ }
291
+ )
292
+ // 负责更新
293
+ watchEffect(() => {
294
+ infos.push(...parseInfo(props.info))
295
+ needSave.value = false
296
+ })
297
+
298
+ // 预计格式
299
+ const resFormat = computed(
300
+ () => `${infos.map((v) => v.text).join(formatData.splitChar)}.后缀`
301
+ )
302
+ watchEffect(() => {
303
+ autoRewrite.value = !!props.rewrite
304
+ })
305
+ const handleChange = (v: boolean) => {
306
+ updateTaskInfo(props.k, {
307
+ rewrite: +v
308
+ })
309
+ }
310
+
311
+ const addInfo = (infoList?: InfoItem[], type?: InfoItemType) => {
312
+ const list = infoList || infos
313
+ const t = type || selectType.value
314
+ const item: InfoItem = { text: `标题${list.length + 1}`, type: t, value: '' }
315
+ if (t === 'radio' || t === 'select') {
316
+ item.children = [{ text: '选项1' }, { text: '选项2' }]
317
+ }
318
+ list.push(item)
319
+ needSave.value = true
320
+ }
321
+ const deleteInfo = (idx: number, infoList?: InfoItem[], minLen = 1) => {
322
+ const list = infoList || infos
323
+ if (list.length <= minLen) {
324
+ return
325
+ }
326
+ list.splice(idx, 1)
327
+ needSave.value = true
328
+ }
329
+ const judgeInfoForm = (items: InfoItem[]) =>
330
+ items.every((v) => v.text.trim() && judgeInfoForm(v.children || []))
331
+ const saveInfo = () => {
332
+ if (!judgeInfoForm(infos)) {
333
+ ElMessage.error('请完整填写表单信息')
334
+ setTimeout(() => {
335
+ ElMessage.warning('不能有空项')
336
+ }, 100)
337
+ return
338
+ }
339
+ updateTaskInfo(props.k, {
340
+ info: JSON.stringify(
341
+ infos.map((v) => {
342
+ // 特殊处理固定值的内容
343
+ if (v.type === 'text') {
344
+ v.value = v.text
345
+ }
346
+ return v
347
+ })
348
+ )
349
+ })
350
+ needSave.value = false
351
+ }
352
+
353
+ const moveInfoUp = (idx: number) => {
354
+ if (idx === 0) return
355
+ const temp = infos[idx - 1]
356
+ infos.splice(idx - 1, 1)
357
+ infos.splice(idx, 0, temp)
358
+ }
359
+
360
+ const importPanelInfo = reactive({ taskList: [], taskValue: '' })
361
+ const showImportPanel = ref(false)
362
+ const openImportPanel = async () => {
363
+ const taskKey = props.k
364
+ // 通过任务Key获取可用任务列表,与概况信息
365
+ const { data } = await TaskApi.getUsefulTemplate(taskKey)
366
+ importPanelInfo.taskList = data
367
+ importPanelInfo.taskValue = data[0]?.taskKey || ''
368
+ showImportPanel.value = true
369
+ }
370
+
371
+ const handleSaveImportInfo = () => {
372
+ const usefulInfo = importPanelInfo.taskList.find(
373
+ (v) => v.taskKey === importPanelInfo.taskValue
374
+ ).info
375
+ infos.splice(0, infos.length)
376
+ infos.push(...parseInfo(usefulInfo))
377
+ showImportPanel.value = false
378
+ needSave.value = true
379
+ }
380
+
381
+ const $store = useStore()
382
+ const isMobile = computed(() => $store.getters['public/isMobile'])
383
+ const importPanelFlexStyle = computed(() => (isMobile.value ? '0 0 auto' : 0.5))
384
+
385
+ const showHelp = () => {
386
+ ElMessageBox.alert(
387
+ '<p>固定内容主要用于重命名中,固定的部分,如“活动名”,“班级名”</p><p>如要设置注意事项,请使用 <strong>批注</strong> 功能</p>',
388
+ '注意事项',
389
+ { dangerouslyUseHTMLString: true }
390
+ )
391
+ }
392
+
393
+ const handleChangeSplitChar = () => {
394
+ updateTaskInfo(props.k, {
395
+ format: JSON.stringify(formatData)
396
+ })
397
+ }
398
+ const splitCharList = reactive(['-', '+', '_'])
399
+ watchEffect(() => {
400
+ if (props.format !== null) {
401
+ Object.assign(formatData, parseFileFormat(props.format))
402
+ }
403
+ })
404
+ </script>
405
+ <style scoped lang="scss">
406
+ .auto-format {
407
+ display: flex;
408
+ justify-content: center;
409
+ }
410
+
411
+ :deep(.el-form-item__label) {
412
+ display: flex;
413
+ justify-content: center;
414
+ align-items: flex-start;
415
+ }
416
+
417
+ .num-wrapper {
418
+ display: flex;
419
+ justify-content: center;
420
+ align-items: center;
421
+ width: 20px;
422
+ height: 20px;
423
+ border-radius: 50%;
424
+ border: 2px solid #000;
425
+ text-align: center;
426
+ font-size: 14px;
427
+ }
428
+
429
+ .info-panel :deep(.el-form-item__label) {
430
+ flex: v-bind(importPanelFlexStyle);
431
+ justify-content: flex-end;
432
+ }
433
+
434
+ .form-wrapper {
435
+ max-width: 380px;
436
+ margin: 0 auto;
437
+ }
438
+
439
+ .form-wrapper :deep(.el-input-group__append) {
440
+ background-color: transparent;
441
+ border: none;
442
+ box-shadow: none;
443
+ padding: 0;
444
+ }
445
+
446
+ .form-item-wrapper {
447
+ width: 50px;
448
+ display: flex;
449
+ justify-content: center;
450
+ align-items: center;
451
+ }
452
+
453
+ .form-item-type {
454
+ margin-left: 10px;
455
+ font-size: 12px;
456
+ width: 48px;
457
+ text-align: left;
458
+ // TODO:待定颜色
459
+ // &.input{
460
+ // color: black;
461
+ // }
462
+ // &.text{
463
+ // color: #000000;
464
+ // }
465
+ // &.radio{
466
+ // color: #999;
467
+ // }
468
+ }
469
+
470
+ .radio-list {
471
+ padding-top: 10px;
472
+ }
473
+
474
+ .radio-list :deep(.el-input) {
475
+ width: 80%;
476
+ }
477
+ </style>